* [PATCH 02/20] e1000: Fix a bug in e1000_detect_gig_phy
[not found] <1453089161-6697-1-git-send-email-andrew.smirnov@gmail.com>
@ 2016-01-18 3:52 ` Andrey Smirnov
2016-01-18 3:52 ` [PATCH 03/20] e1000: Remove unnecessary variable Andrey Smirnov
` (17 subsequent siblings)
18 siblings, 0 replies; 22+ messages in thread
From: Andrey Smirnov @ 2016-01-18 3:52 UTC (permalink / raw)
To: barebox; +Cc: Andrey Smirnov
It seems there's stray exclamation mark character in
e1000_detect_gig_phy which renders the whole if statement useless
since it converts 'phy_type' into a boolean and comparing that to 0xFF
would always result in false (which GCC 5.1 is now able to detect and
warn about). This commit fixes that.
Signed-off-by: Andrey Smirnov <andrew.smirnov@gmail.com>
---
drivers/net/e1000/main.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/net/e1000/main.c b/drivers/net/e1000/main.c
index 552b0dc..05c3a78 100644
--- a/drivers/net/e1000/main.c
+++ b/drivers/net/e1000/main.c
@@ -3097,7 +3097,7 @@ static int32_t e1000_detect_gig_phy(struct e1000_hw *hw)
return -E1000_ERR_CONFIG;
}
- if (!phy_type == e1000_phy_undefined) {
+ if (phy_type == e1000_phy_undefined) {
dev_dbg(hw->dev, "Invalid PHY ID 0x%X\n", hw->phy_id);
return -EINVAL;
}
--
2.5.0
_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox
^ permalink raw reply [flat|nested] 22+ messages in thread
* [PATCH 03/20] e1000: Remove unnecessary variable
[not found] <1453089161-6697-1-git-send-email-andrew.smirnov@gmail.com>
2016-01-18 3:52 ` [PATCH 02/20] e1000: Fix a bug in e1000_detect_gig_phy Andrey Smirnov
@ 2016-01-18 3:52 ` Andrey Smirnov
2016-01-18 3:52 ` [PATCH 04/20] e1000: Do not read same register twice Andrey Smirnov
` (16 subsequent siblings)
18 siblings, 0 replies; 22+ messages in thread
From: Andrey Smirnov @ 2016-01-18 3:52 UTC (permalink / raw)
To: barebox; +Cc: Andrey Smirnov
There doesn't seem to be any point for having 'nv_packet' variable and
it looks like a leftover from driving porting. Remove it and use
'txpacket' instead
Signed-off-by: Andrey Smirnov <andrew.smirnov@gmail.com>
---
drivers/net/e1000/main.c | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/drivers/net/e1000/main.c b/drivers/net/e1000/main.c
index 05c3a78..66ec72f 100644
--- a/drivers/net/e1000/main.c
+++ b/drivers/net/e1000/main.c
@@ -3397,7 +3397,6 @@ static int e1000_poll(struct eth_device *edev)
static int e1000_transmit(struct eth_device *edev, void *txpacket, int length)
{
- void *nv_packet = (void *)txpacket;
struct e1000_hw *hw = edev->priv;
volatile struct e1000_tx_desc *txp;
uint64_t to;
@@ -3405,7 +3404,7 @@ static int e1000_transmit(struct eth_device *edev, void *txpacket, int length)
txp = hw->tx_base + hw->tx_tail;
hw->tx_tail = (hw->tx_tail + 1) % 8;
- txp->buffer_addr = cpu_to_le64(virt_to_bus(hw->pdev, nv_packet));
+ txp->buffer_addr = cpu_to_le64(virt_to_bus(hw->pdev, txpacket));
txp->lower.data = cpu_to_le32(hw->txd_cmd | length);
txp->upper.data = 0;
--
2.5.0
_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox
^ permalink raw reply [flat|nested] 22+ messages in thread
* [PATCH 04/20] e1000: Do not read same register twice
[not found] <1453089161-6697-1-git-send-email-andrew.smirnov@gmail.com>
2016-01-18 3:52 ` [PATCH 02/20] e1000: Fix a bug in e1000_detect_gig_phy Andrey Smirnov
2016-01-18 3:52 ` [PATCH 03/20] e1000: Remove unnecessary variable Andrey Smirnov
@ 2016-01-18 3:52 ` Andrey Smirnov
2016-01-18 3:52 ` [PATCH 05/20] e1000: Remove unneeded i210 specific register code Andrey Smirnov
` (15 subsequent siblings)
18 siblings, 0 replies; 22+ messages in thread
From: Andrey Smirnov @ 2016-01-18 3:52 UTC (permalink / raw)
To: barebox; +Cc: Andrey Smirnov
EEPROM_INIT_CONTROL2_REG is already read once before entering this
switch statement, so there's not much use in reading its value for the
second time.
Signed-off-by: Andrey Smirnov <andrew.smirnov@gmail.com>
---
drivers/net/e1000/main.c | 6 ------
1 file changed, 6 deletions(-)
diff --git a/drivers/net/e1000/main.c b/drivers/net/e1000/main.c
index 66ec72f..84459da 100644
--- a/drivers/net/e1000/main.c
+++ b/drivers/net/e1000/main.c
@@ -840,12 +840,6 @@ static int e1000_setup_link(struct e1000_hw *hw)
hw->fc = e1000_fc_full;
break;
default:
- ret_val = e1000_read_eeprom(hw, EEPROM_INIT_CONTROL2_REG, 1, &eeprom_data);
- if (ret_val) {
- dev_dbg(hw->dev, "EEPROM Read Error\n");
- return -E1000_ERR_EEPROM;
- }
-
if ((eeprom_data & EEPROM_WORD0F_PAUSE_MASK) == 0)
hw->fc = e1000_fc_none;
else if ((eeprom_data & EEPROM_WORD0F_PAUSE_MASK) == EEPROM_WORD0F_ASM_DIR)
--
2.5.0
_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox
^ permalink raw reply [flat|nested] 22+ messages in thread
* [PATCH 05/20] e1000: Remove unneeded i210 specific register code
[not found] <1453089161-6697-1-git-send-email-andrew.smirnov@gmail.com>
` (2 preceding siblings ...)
2016-01-18 3:52 ` [PATCH 04/20] e1000: Do not read same register twice Andrey Smirnov
@ 2016-01-18 3:52 ` Andrey Smirnov
2016-01-18 3:52 ` [PATCH 06/20] e1000: Consolidate register offset fixups Andrey Smirnov
` (14 subsequent siblings)
18 siblings, 0 replies; 22+ messages in thread
From: Andrey Smirnov @ 2016-01-18 3:52 UTC (permalink / raw)
To: barebox; +Cc: Andrey Smirnov
Despite having EEC(EECD) and EERD at "non-standard" offsets i210
aliases those registers to be accesible via regular addresses so none
of the code removed by this commit is really necessary.
Signed-off-by: Andrey Smirnov <andrew.smirnov@gmail.com>
---
drivers/net/e1000/e1000.h | 2 --
drivers/net/e1000/eeprom.c | 25 +++++--------------------
drivers/net/e1000/main.c | 4 ++--
3 files changed, 7 insertions(+), 24 deletions(-)
diff --git a/drivers/net/e1000/e1000.h b/drivers/net/e1000/e1000.h
index 82ff32e..7bc8825 100644
--- a/drivers/net/e1000/e1000.h
+++ b/drivers/net/e1000/e1000.h
@@ -415,9 +415,7 @@ struct e1000_tx_desc {
#define E1000_CTRL 0x00000 /* Device Control - RW */
#define E1000_STATUS 0x00008 /* Device Status - RO */
#define E1000_EECD 0x00010 /* EEPROM/Flash Control - RW */
-#define E1000_I210_EECD 0x12010 /* EEPROM/Flash Control - RW */
#define E1000_EERD 0x00014 /* EEPROM Read - RW */
-#define E1000_I210_EERD 0x12014 /* EEPROM Read - RW */
#define E1000_CTRL_EXT 0x00018 /* Extended Device Control - RW */
#define E1000_MDIC 0x00020 /* MDI Control - RW */
#define E1000_FCAL 0x00028 /* Flow Control Address Low - RW */
diff --git a/drivers/net/e1000/eeprom.c b/drivers/net/e1000/eeprom.c
index fb39a85..1fa437e 100644
--- a/drivers/net/e1000/eeprom.c
+++ b/drivers/net/e1000/eeprom.c
@@ -275,10 +275,7 @@ int32_t e1000_init_eeprom_params(struct e1000_hw *hw)
int32_t ret_val = E1000_SUCCESS;
uint16_t eeprom_size;
- if (hw->mac_type == e1000_igb)
- eecd = E1000_READ_REG(hw, I210_EECD);
- else
- eecd = E1000_READ_REG(hw, EECD);
+ eecd = E1000_READ_REG(hw, EECD);
DEBUGFUNC();
@@ -456,10 +453,7 @@ static int32_t e1000_poll_eerd_eewr_done(struct e1000_hw *hw, int eerd)
for (i = 0; i < attempts; i++) {
if (eerd == E1000_EEPROM_POLL_READ) {
- if (hw->mac_type == e1000_igb)
- reg = E1000_READ_REG(hw, I210_EERD);
- else
- reg = E1000_READ_REG(hw, EERD);
+ reg = E1000_READ_REG(hw, EERD);
} else {
if (hw->mac_type == e1000_igb)
reg = E1000_READ_REG(hw, I210_EEWR);
@@ -497,24 +491,15 @@ static int32_t e1000_read_eeprom_eerd(struct e1000_hw *hw,
eerd = ((offset+i) << E1000_EEPROM_RW_ADDR_SHIFT) +
E1000_EEPROM_RW_REG_START;
- if (hw->mac_type == e1000_igb)
- E1000_WRITE_REG(hw, I210_EERD, eerd);
- else
- E1000_WRITE_REG(hw, EERD, eerd);
+ E1000_WRITE_REG(hw, EERD, eerd);
error = e1000_poll_eerd_eewr_done(hw, E1000_EEPROM_POLL_READ);
if (error)
break;
- if (hw->mac_type == e1000_igb) {
- data[i] = (E1000_READ_REG(hw, I210_EERD) >>
- E1000_EEPROM_RW_REG_DATA);
- } else {
- data[i] = (E1000_READ_REG(hw, EERD) >>
- E1000_EEPROM_RW_REG_DATA);
- }
-
+ data[i] = (E1000_READ_REG(hw, EERD) >>
+ E1000_EEPROM_RW_REG_DATA);
}
return error;
diff --git a/drivers/net/e1000/main.c b/drivers/net/e1000/main.c
index 84459da..a29ceb1 100644
--- a/drivers/net/e1000/main.c
+++ b/drivers/net/e1000/main.c
@@ -550,7 +550,7 @@ static void e1000_reset_hw(struct e1000_hw *hw)
reg = E1000_READ_REG(hw, STATUS);
if (reg & E1000_STATUS_PF_RST_DONE)
dev_dbg(hw->dev, "PF OK\n");
- reg = E1000_READ_REG(hw, I210_EECD);
+ reg = E1000_READ_REG(hw, EECD);
if (reg & E1000_EECD_AUTO_RD)
dev_dbg(hw->dev, "EEC OK\n");
} else if (hw->mac_type < e1000_82540) {
@@ -3565,7 +3565,7 @@ static int e1000_probe(struct pci_dev *pdev, const struct pci_device_id *id)
dev_err(&pdev->dev, "EEPROM is invalid!\n");
return -EINVAL;
}
- if ((E1000_READ_REG(hw, I210_EECD) & E1000_EECD_FLUPD) &&
+ if ((E1000_READ_REG(hw, EECD) & E1000_EECD_FLUPD) &&
e1000_validate_eeprom_checksum(hw))
return -EINVAL;
--
2.5.0
_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox
^ permalink raw reply [flat|nested] 22+ messages in thread
* [PATCH 06/20] e1000: Consolidate register offset fixups
[not found] <1453089161-6697-1-git-send-email-andrew.smirnov@gmail.com>
` (3 preceding siblings ...)
2016-01-18 3:52 ` [PATCH 05/20] e1000: Remove unneeded i210 specific register code Andrey Smirnov
@ 2016-01-18 3:52 ` Andrey Smirnov
2016-01-18 3:52 ` [PATCH 07/20] e1000: Remove 'use_eewr' parameter Andrey Smirnov
` (13 subsequent siblings)
18 siblings, 0 replies; 22+ messages in thread
From: Andrey Smirnov @ 2016-01-18 3:52 UTC (permalink / raw)
To: barebox; +Cc: Andrey Smirnov
Consolidate all code taking care on CSR offset differences for i210
chips into a single place in the driver and integrate that
funcionality into E1000_{READ,WRITE}_REG macros. This way we can get
rid of all those
if (hw->mac_type == e1000_igb) {
....
} else {
....
}
snippets sprinkled all across the driver code.
Signed-off-by: Andrey Smirnov <andrew.smirnov@gmail.com>
---
drivers/net/e1000/e1000.h | 41 +++++++++++++++++++++++++++++++++++++++--
drivers/net/e1000/eeprom.c | 10 +++-------
drivers/net/e1000/main.c | 17 +++++------------
3 files changed, 47 insertions(+), 21 deletions(-)
diff --git a/drivers/net/e1000/e1000.h b/drivers/net/e1000/e1000.h
index 7bc8825..0d5b265 100644
--- a/drivers/net/e1000/e1000.h
+++ b/drivers/net/e1000/e1000.h
@@ -29,9 +29,9 @@
/* I/O wrapper functions */
#define E1000_WRITE_REG(a, reg, value) \
- writel((value), ((a)->hw_addr + E1000_##reg))
+ e1000_write_reg((a), E1000_##reg, (value))
#define E1000_READ_REG(a, reg) \
- readl((a)->hw_addr + E1000_##reg)
+ e1000_read_reg((a), E1000_##reg)
#define E1000_WRITE_REG_ARRAY(a, reg, offset, value) \
writel((value), ((a)->hw_addr + E1000_##reg + ((offset) << 2)))
#define E1000_READ_REG_ARRAY(a, reg, offset) \
@@ -2133,5 +2133,42 @@ int32_t e1000_read_eeprom(struct e1000_hw *hw, uint16_t offset,
int32_t e1000_swfw_sync_acquire(struct e1000_hw *hw, uint16_t mask);
+struct e1000_fixup_table {
+ uint32_t orig, fixed;
+};
+
+static inline uint32_t e1000_true_offset(struct e1000_hw *hw, uint32_t reg)
+{
+ if (hw->mac_type == e1000_igb) {
+ unsigned int i;
+
+ const struct e1000_fixup_table fixup_table[] = {
+ { E1000_EEWR, E1000_I210_EEWR },
+ { E1000_PHY_CTRL, E1000_I210_PHY_CTRL },
+ { E1000_EEMNGCTL, E1000_I210_EEMNGCTL },
+ };
+
+ for (i = 0; i < ARRAY_SIZE(fixup_table); i++) {
+ if (fixup_table[i].orig == reg)
+ return fixup_table[i].fixed;
+ }
+ }
+
+ return reg;
+}
+
+static inline void e1000_write_reg(struct e1000_hw *hw, uint32_t reg, uint32_t value)
+{
+ reg = e1000_true_offset(hw, reg);
+ writel(value, hw->hw_addr + reg);
+}
+
+static inline uint32_t e1000_read_reg(struct e1000_hw *hw, uint32_t reg)
+{
+ reg = e1000_true_offset(hw, reg);
+ return readl(hw->hw_addr + reg);
+}
+
+
#endif /* _E1000_HW_H_ */
diff --git a/drivers/net/e1000/eeprom.c b/drivers/net/e1000/eeprom.c
index 1fa437e..b99b96b 100644
--- a/drivers/net/e1000/eeprom.c
+++ b/drivers/net/e1000/eeprom.c
@@ -452,14 +452,10 @@ static int32_t e1000_poll_eerd_eewr_done(struct e1000_hw *hw, int eerd)
int32_t done = E1000_ERR_EEPROM;
for (i = 0; i < attempts; i++) {
- if (eerd == E1000_EEPROM_POLL_READ) {
+ if (eerd == E1000_EEPROM_POLL_READ)
reg = E1000_READ_REG(hw, EERD);
- } else {
- if (hw->mac_type == e1000_igb)
- reg = E1000_READ_REG(hw, I210_EEWR);
- else
- reg = E1000_READ_REG(hw, EEWR);
- }
+ else
+ reg = E1000_READ_REG(hw, EEWR);
if (reg & E1000_EEPROM_RW_REG_DONE) {
done = E1000_SUCCESS;
diff --git a/drivers/net/e1000/main.c b/drivers/net/e1000/main.c
index a29ceb1..9791b60 100644
--- a/drivers/net/e1000/main.c
+++ b/drivers/net/e1000/main.c
@@ -1185,14 +1185,11 @@ static int32_t e1000_set_d0_lplu_state_off(struct e1000_hw *hw)
if (hw->mac_type <= e1000_82547_rev_2)
return E1000_SUCCESS;
- if (hw->mac_type == e1000_ich8lan) {
+ if (hw->mac_type == e1000_ich8lan ||
+ hw->mac_type == e1000_igb) {
phy_ctrl = E1000_READ_REG(hw, PHY_CTRL);
phy_ctrl &= ~E1000_PHY_CTRL_D0A_LPLU;
E1000_WRITE_REG(hw, PHY_CTRL, phy_ctrl);
- } else if (hw->mac_type == e1000_igb) {
- phy_ctrl = E1000_READ_REG(hw, I210_PHY_CTRL);
- phy_ctrl &= ~E1000_PHY_CTRL_D0A_LPLU;
- E1000_WRITE_REG(hw, I210_PHY_CTRL, phy_ctrl);
} else {
ret_val = e1000_read_phy_reg(hw, IGP02E1000_PHY_POWER_MGMT,
&phy_data);
@@ -2746,13 +2743,9 @@ static int32_t e1000_get_phy_cfg_done(struct e1000_hw *hw)
case e1000_82572:
case e1000_igb:
while (timeout) {
- if (hw->mac_type == e1000_igb) {
- if (E1000_READ_REG(hw, I210_EEMNGCTL) & cfg_mask)
- break;
- } else {
- if (E1000_READ_REG(hw, EEMNGCTL) & cfg_mask)
- break;
- }
+ if (E1000_READ_REG(hw, EEMNGCTL) & cfg_mask)
+ break;
+
mdelay(1);
timeout--;
}
--
2.5.0
_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox
^ permalink raw reply [flat|nested] 22+ messages in thread
* [PATCH 07/20] e1000: Remove 'use_eewr' parameter
[not found] <1453089161-6697-1-git-send-email-andrew.smirnov@gmail.com>
` (4 preceding siblings ...)
2016-01-18 3:52 ` [PATCH 06/20] e1000: Consolidate register offset fixups Andrey Smirnov
@ 2016-01-18 3:52 ` Andrey Smirnov
2016-01-18 3:52 ` [PATCH 08/20] e1000: Remove 'page_size' Andrey Smirnov
` (12 subsequent siblings)
18 siblings, 0 replies; 22+ messages in thread
From: Andrey Smirnov @ 2016-01-18 3:52 UTC (permalink / raw)
To: barebox; +Cc: Andrey Smirnov
Remove 'use_eewr' from 'struct e1000_eeprom_info' since it is not used
anywhere in the code.
Signed-off-by: Andrey Smirnov <andrew.smirnov@gmail.com>
---
drivers/net/e1000/e1000.h | 1 -
drivers/net/e1000/eeprom.c | 7 -------
2 files changed, 8 deletions(-)
diff --git a/drivers/net/e1000/e1000.h b/drivers/net/e1000/e1000.h
index 0d5b265..97fe52f 100644
--- a/drivers/net/e1000/e1000.h
+++ b/drivers/net/e1000/e1000.h
@@ -701,7 +701,6 @@ struct e1000_eeprom_info {
uint16_t delay_usec;
uint16_t page_size;
bool use_eerd;
- bool use_eewr;
};
#define E1000_EEPROM_SWDPIN0 0x0001 /* SWDPIN 0 EEPROM Value */
diff --git a/drivers/net/e1000/eeprom.c b/drivers/net/e1000/eeprom.c
index b99b96b..7b4c77d 100644
--- a/drivers/net/e1000/eeprom.c
+++ b/drivers/net/e1000/eeprom.c
@@ -290,7 +290,6 @@ int32_t e1000_init_eeprom_params(struct e1000_hw *hw)
eeprom->address_bits = 6;
eeprom->delay_usec = 50;
eeprom->use_eerd = false;
- eeprom->use_eewr = false;
break;
case e1000_82540:
case e1000_82545:
@@ -308,7 +307,6 @@ int32_t e1000_init_eeprom_params(struct e1000_hw *hw)
eeprom->address_bits = 6;
}
eeprom->use_eerd = false;
- eeprom->use_eewr = false;
break;
case e1000_82541:
case e1000_82541_rev_2:
@@ -338,7 +336,6 @@ int32_t e1000_init_eeprom_params(struct e1000_hw *hw)
}
}
eeprom->use_eerd = false;
- eeprom->use_eewr = false;
break;
case e1000_82571:
case e1000_82572:
@@ -353,7 +350,6 @@ int32_t e1000_init_eeprom_params(struct e1000_hw *hw)
eeprom->address_bits = 8;
}
eeprom->use_eerd = false;
- eeprom->use_eewr = false;
break;
case e1000_82573:
case e1000_82574:
@@ -369,7 +365,6 @@ int32_t e1000_init_eeprom_params(struct e1000_hw *hw)
}
if (e1000_is_onboard_nvm_eeprom(hw) == false) {
eeprom->use_eerd = true;
- eeprom->use_eewr = true;
eeprom->type = e1000_eeprom_flash;
eeprom->word_size = 2048;
@@ -392,7 +387,6 @@ int32_t e1000_init_eeprom_params(struct e1000_hw *hw)
eeprom->address_bits = 8;
}
eeprom->use_eerd = true;
- eeprom->use_eewr = false;
break;
case e1000_igb:
/* i210 has 4k of iNVM mapped as EEPROM */
@@ -402,7 +396,6 @@ int32_t e1000_init_eeprom_params(struct e1000_hw *hw)
eeprom->page_size = 32;
eeprom->address_bits = 16;
eeprom->use_eerd = true;
- eeprom->use_eewr = false;
break;
default:
break;
--
2.5.0
_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox
^ permalink raw reply [flat|nested] 22+ messages in thread
* [PATCH 08/20] e1000: Remove 'page_size'
[not found] <1453089161-6697-1-git-send-email-andrew.smirnov@gmail.com>
` (5 preceding siblings ...)
2016-01-18 3:52 ` [PATCH 07/20] e1000: Remove 'use_eewr' parameter Andrey Smirnov
@ 2016-01-18 3:52 ` Andrey Smirnov
2016-01-18 3:52 ` [PATCH 09/20] e1000: Simplify EEPROM init for e1000_80003es2lan Andrey Smirnov
` (11 subsequent siblings)
18 siblings, 0 replies; 22+ messages in thread
From: Andrey Smirnov @ 2016-01-18 3:52 UTC (permalink / raw)
To: barebox; +Cc: Andrey Smirnov
Remove 'page_size' from 'struct e1000_eeprom_info' since it is not
used anywhere in the code.
Signed-off-by: Andrey Smirnov <andrew.smirnov@gmail.com>
---
drivers/net/e1000/e1000.h | 1 -
drivers/net/e1000/eeprom.c | 32 +++++++++++---------------------
2 files changed, 11 insertions(+), 22 deletions(-)
diff --git a/drivers/net/e1000/e1000.h b/drivers/net/e1000/e1000.h
index 97fe52f..8ec45a7 100644
--- a/drivers/net/e1000/e1000.h
+++ b/drivers/net/e1000/e1000.h
@@ -699,7 +699,6 @@ struct e1000_eeprom_info {
uint16_t opcode_bits;
uint16_t address_bits;
uint16_t delay_usec;
- uint16_t page_size;
bool use_eerd;
};
diff --git a/drivers/net/e1000/eeprom.c b/drivers/net/e1000/eeprom.c
index 7b4c77d..0cd0bf5 100644
--- a/drivers/net/e1000/eeprom.c
+++ b/drivers/net/e1000/eeprom.c
@@ -316,13 +316,10 @@ int32_t e1000_init_eeprom_params(struct e1000_hw *hw)
eeprom->type = e1000_eeprom_spi;
eeprom->opcode_bits = 8;
eeprom->delay_usec = 1;
- if (eecd & E1000_EECD_ADDR_BITS) {
- eeprom->page_size = 32;
+ if (eecd & E1000_EECD_ADDR_BITS)
eeprom->address_bits = 16;
- } else {
- eeprom->page_size = 8;
+ else
eeprom->address_bits = 8;
- }
} else {
eeprom->type = e1000_eeprom_microwire;
eeprom->opcode_bits = 3;
@@ -342,13 +339,11 @@ int32_t e1000_init_eeprom_params(struct e1000_hw *hw)
eeprom->type = e1000_eeprom_spi;
eeprom->opcode_bits = 8;
eeprom->delay_usec = 1;
- if (eecd & E1000_EECD_ADDR_BITS) {
- eeprom->page_size = 32;
+ if (eecd & E1000_EECD_ADDR_BITS)
eeprom->address_bits = 16;
- } else {
- eeprom->page_size = 8;
+ else
eeprom->address_bits = 8;
- }
+
eeprom->use_eerd = false;
break;
case e1000_82573:
@@ -356,13 +351,11 @@ int32_t e1000_init_eeprom_params(struct e1000_hw *hw)
eeprom->type = e1000_eeprom_spi;
eeprom->opcode_bits = 8;
eeprom->delay_usec = 1;
- if (eecd & E1000_EECD_ADDR_BITS) {
- eeprom->page_size = 32;
+ if (eecd & E1000_EECD_ADDR_BITS)
eeprom->address_bits = 16;
- } else {
- eeprom->page_size = 8;
+ else
eeprom->address_bits = 8;
- }
+
if (e1000_is_onboard_nvm_eeprom(hw) == false) {
eeprom->use_eerd = true;
@@ -379,13 +372,11 @@ int32_t e1000_init_eeprom_params(struct e1000_hw *hw)
eeprom->type = e1000_eeprom_spi;
eeprom->opcode_bits = 8;
eeprom->delay_usec = 1;
- if (eecd & E1000_EECD_ADDR_BITS) {
- eeprom->page_size = 32;
+ if (eecd & E1000_EECD_ADDR_BITS)
eeprom->address_bits = 16;
- } else {
- eeprom->page_size = 8;
+ else
eeprom->address_bits = 8;
- }
+
eeprom->use_eerd = true;
break;
case e1000_igb:
@@ -393,7 +384,6 @@ int32_t e1000_init_eeprom_params(struct e1000_hw *hw)
eeprom->type = e1000_eeprom_invm;
eeprom->opcode_bits = 8;
eeprom->delay_usec = 1;
- eeprom->page_size = 32;
eeprom->address_bits = 16;
eeprom->use_eerd = true;
break;
--
2.5.0
_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox
^ permalink raw reply [flat|nested] 22+ messages in thread
* [PATCH 09/20] e1000: Simplify EEPROM init for e1000_80003es2lan
[not found] <1453089161-6697-1-git-send-email-andrew.smirnov@gmail.com>
` (6 preceding siblings ...)
2016-01-18 3:52 ` [PATCH 08/20] e1000: Remove 'page_size' Andrey Smirnov
@ 2016-01-18 3:52 ` Andrey Smirnov
2016-01-18 3:52 ` [PATCH 10/20] e1000: Simplify EEPROM init for e1000_igb Andrey Smirnov
` (10 subsequent siblings)
18 siblings, 0 replies; 22+ messages in thread
From: Andrey Smirnov @ 2016-01-18 3:52 UTC (permalink / raw)
To: barebox; +Cc: Andrey Smirnov
That chip specifies read access uising EERD via use_eerd, which means
that none of the more "advanced" EEPROM parameters will be used for
reads, so remove them.
Signed-off-by: Andrey Smirnov <andrew.smirnov@gmail.com>
---
drivers/net/e1000/eeprom.c | 7 -------
1 file changed, 7 deletions(-)
diff --git a/drivers/net/e1000/eeprom.c b/drivers/net/e1000/eeprom.c
index 0cd0bf5..1abd630 100644
--- a/drivers/net/e1000/eeprom.c
+++ b/drivers/net/e1000/eeprom.c
@@ -370,13 +370,6 @@ int32_t e1000_init_eeprom_params(struct e1000_hw *hw)
break;
case e1000_80003es2lan:
eeprom->type = e1000_eeprom_spi;
- eeprom->opcode_bits = 8;
- eeprom->delay_usec = 1;
- if (eecd & E1000_EECD_ADDR_BITS)
- eeprom->address_bits = 16;
- else
- eeprom->address_bits = 8;
-
eeprom->use_eerd = true;
break;
case e1000_igb:
--
2.5.0
_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox
^ permalink raw reply [flat|nested] 22+ messages in thread
* [PATCH 10/20] e1000: Simplify EEPROM init for e1000_igb
[not found] <1453089161-6697-1-git-send-email-andrew.smirnov@gmail.com>
` (7 preceding siblings ...)
2016-01-18 3:52 ` [PATCH 09/20] e1000: Simplify EEPROM init for e1000_80003es2lan Andrey Smirnov
@ 2016-01-18 3:52 ` Andrey Smirnov
2016-01-18 3:52 ` [PATCH 11/20] e1000: Consolidate SPI EEPROM init code Andrey Smirnov
` (9 subsequent siblings)
18 siblings, 0 replies; 22+ messages in thread
From: Andrey Smirnov @ 2016-01-18 3:52 UTC (permalink / raw)
To: barebox; +Cc: Andrey Smirnov
That chip specifies read access uising EERD via use_eerd, which means
that none of the more "advanced" EEPROM parameters will be used for
reads, so remove them.
Signed-off-by: Andrey Smirnov <andrew.smirnov@gmail.com>
---
drivers/net/e1000/eeprom.c | 3 ---
1 file changed, 3 deletions(-)
diff --git a/drivers/net/e1000/eeprom.c b/drivers/net/e1000/eeprom.c
index 1abd630..ef2cc6b 100644
--- a/drivers/net/e1000/eeprom.c
+++ b/drivers/net/e1000/eeprom.c
@@ -375,9 +375,6 @@ int32_t e1000_init_eeprom_params(struct e1000_hw *hw)
case e1000_igb:
/* i210 has 4k of iNVM mapped as EEPROM */
eeprom->type = e1000_eeprom_invm;
- eeprom->opcode_bits = 8;
- eeprom->delay_usec = 1;
- eeprom->address_bits = 16;
eeprom->use_eerd = true;
break;
default:
--
2.5.0
_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox
^ permalink raw reply [flat|nested] 22+ messages in thread
* [PATCH 11/20] e1000: Consolidate SPI EEPROM init code
[not found] <1453089161-6697-1-git-send-email-andrew.smirnov@gmail.com>
` (8 preceding siblings ...)
2016-01-18 3:52 ` [PATCH 10/20] e1000: Simplify EEPROM init for e1000_igb Andrey Smirnov
@ 2016-01-18 3:52 ` Andrey Smirnov
2016-01-18 3:52 ` [PATCH 12/20] e1000: Consolidate Microwire " Andrey Smirnov
` (8 subsequent siblings)
18 siblings, 0 replies; 22+ messages in thread
From: Andrey Smirnov @ 2016-01-18 3:52 UTC (permalink / raw)
To: barebox; +Cc: Andrey Smirnov
All of the chips that bitbang SPI to access EEPROM appear to be
configured in the same way, so move common code into a separate
function and make use of it.
Signed-off-by: Andrey Smirnov <andrew.smirnov@gmail.com>
---
drivers/net/e1000/eeprom.c | 46 +++++++++++++++++++++-------------------------
1 file changed, 21 insertions(+), 25 deletions(-)
diff --git a/drivers/net/e1000/eeprom.c b/drivers/net/e1000/eeprom.c
index ef2cc6b..f6377b7 100644
--- a/drivers/net/e1000/eeprom.c
+++ b/drivers/net/e1000/eeprom.c
@@ -261,6 +261,22 @@ static int32_t e1000_acquire_eeprom(struct e1000_hw *hw)
return E1000_SUCCESS;
}
+static void e1000_eeprom_uses_spi(struct e1000_eeprom_info *eeprom,
+ uint32_t eecd)
+{
+ eeprom->type = e1000_eeprom_spi;
+ eeprom->opcode_bits = 8;
+ eeprom->delay_usec = 1;
+ if (eecd & E1000_EECD_ADDR_BITS) {
+ eeprom->address_bits = 16;
+ } else {
+ eeprom->address_bits = 8;
+ }
+
+ eeprom->use_eerd = false;
+}
+
+
/******************************************************************************
* Sets up eeprom variables in the hw struct. Must be called after mac_type
* is configured. Additionally, if this is ICH8, the flash controller GbE
@@ -313,13 +329,7 @@ int32_t e1000_init_eeprom_params(struct e1000_hw *hw)
case e1000_82547:
case e1000_82547_rev_2:
if (eecd & E1000_EECD_TYPE) {
- eeprom->type = e1000_eeprom_spi;
- eeprom->opcode_bits = 8;
- eeprom->delay_usec = 1;
- if (eecd & E1000_EECD_ADDR_BITS)
- eeprom->address_bits = 16;
- else
- eeprom->address_bits = 8;
+ e1000_eeprom_uses_spi(eeprom, eecd);
} else {
eeprom->type = e1000_eeprom_microwire;
eeprom->opcode_bits = 3;
@@ -336,27 +346,13 @@ int32_t e1000_init_eeprom_params(struct e1000_hw *hw)
break;
case e1000_82571:
case e1000_82572:
- eeprom->type = e1000_eeprom_spi;
- eeprom->opcode_bits = 8;
- eeprom->delay_usec = 1;
- if (eecd & E1000_EECD_ADDR_BITS)
- eeprom->address_bits = 16;
- else
- eeprom->address_bits = 8;
-
- eeprom->use_eerd = false;
+ e1000_eeprom_uses_spi(eeprom, eecd);
break;
case e1000_82573:
case e1000_82574:
- eeprom->type = e1000_eeprom_spi;
- eeprom->opcode_bits = 8;
- eeprom->delay_usec = 1;
- if (eecd & E1000_EECD_ADDR_BITS)
- eeprom->address_bits = 16;
- else
- eeprom->address_bits = 8;
-
- if (e1000_is_onboard_nvm_eeprom(hw) == false) {
+ if (e1000_is_onboard_nvm_eeprom(hw)) {
+ e1000_eeprom_uses_spi(eeprom, eecd);
+ } else {
eeprom->use_eerd = true;
eeprom->type = e1000_eeprom_flash;
--
2.5.0
_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox
^ permalink raw reply [flat|nested] 22+ messages in thread
* [PATCH 12/20] e1000: Consolidate Microwire EEPROM init code
[not found] <1453089161-6697-1-git-send-email-andrew.smirnov@gmail.com>
` (9 preceding siblings ...)
2016-01-18 3:52 ` [PATCH 11/20] e1000: Consolidate SPI EEPROM init code Andrey Smirnov
@ 2016-01-18 3:52 ` Andrey Smirnov
2016-01-18 3:52 ` [PATCH 13/20] e1000: Fix a bug in e1000_probe() Andrey Smirnov
` (7 subsequent siblings)
18 siblings, 0 replies; 22+ messages in thread
From: Andrey Smirnov @ 2016-01-18 3:52 UTC (permalink / raw)
To: barebox; +Cc: Andrey Smirnov
All of the chips that bitbang Microwire to access EEPROM appear to be
configured in the same way, so move common code into a separate
function and make use of it.
Signed-off-by: Andrey Smirnov <andrew.smirnov@gmail.com>
---
drivers/net/e1000/eeprom.c | 52 +++++++++++++++++++---------------------------
1 file changed, 21 insertions(+), 31 deletions(-)
diff --git a/drivers/net/e1000/eeprom.c b/drivers/net/e1000/eeprom.c
index f6377b7..87ea82f 100644
--- a/drivers/net/e1000/eeprom.c
+++ b/drivers/net/e1000/eeprom.c
@@ -276,6 +276,22 @@ static void e1000_eeprom_uses_spi(struct e1000_eeprom_info *eeprom,
eeprom->use_eerd = false;
}
+static void e1000_eeprom_uses_microwire(struct e1000_eeprom_info *eeprom,
+ uint32_t eecd)
+{
+ eeprom->type = e1000_eeprom_microwire;
+ eeprom->opcode_bits = 3;
+ eeprom->delay_usec = 50;
+ if (eecd & E1000_EECD_SIZE) {
+ eeprom->word_size = 256;
+ eeprom->address_bits = 8;
+ } else {
+ eeprom->word_size = 64;
+ eeprom->address_bits = 6;
+ }
+ eeprom->use_eerd = false;
+}
+
/******************************************************************************
* Sets up eeprom variables in the hw struct. Must be called after mac_type
@@ -300,49 +316,23 @@ int32_t e1000_init_eeprom_params(struct e1000_hw *hw)
case e1000_82542_rev2_1:
case e1000_82543:
case e1000_82544:
- eeprom->type = e1000_eeprom_microwire;
- eeprom->word_size = 64;
- eeprom->opcode_bits = 3;
- eeprom->address_bits = 6;
- eeprom->delay_usec = 50;
- eeprom->use_eerd = false;
+ e1000_eeprom_uses_microwire(eeprom, 0);
break;
case e1000_82540:
case e1000_82545:
case e1000_82545_rev_3:
case e1000_82546:
case e1000_82546_rev_3:
- eeprom->type = e1000_eeprom_microwire;
- eeprom->opcode_bits = 3;
- eeprom->delay_usec = 50;
- if (eecd & E1000_EECD_SIZE) {
- eeprom->word_size = 256;
- eeprom->address_bits = 8;
- } else {
- eeprom->word_size = 64;
- eeprom->address_bits = 6;
- }
- eeprom->use_eerd = false;
+ e1000_eeprom_uses_microwire(eeprom, eecd);
break;
case e1000_82541:
case e1000_82541_rev_2:
case e1000_82547:
case e1000_82547_rev_2:
- if (eecd & E1000_EECD_TYPE) {
+ if (eecd & E1000_EECD_TYPE)
e1000_eeprom_uses_spi(eeprom, eecd);
- } else {
- eeprom->type = e1000_eeprom_microwire;
- eeprom->opcode_bits = 3;
- eeprom->delay_usec = 50;
- if (eecd & E1000_EECD_ADDR_BITS) {
- eeprom->word_size = 256;
- eeprom->address_bits = 8;
- } else {
- eeprom->word_size = 64;
- eeprom->address_bits = 6;
- }
- }
- eeprom->use_eerd = false;
+ else
+ e1000_eeprom_uses_microwire(eeprom, eecd);
break;
case e1000_82571:
case e1000_82572:
--
2.5.0
_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox
^ permalink raw reply [flat|nested] 22+ messages in thread
* [PATCH 13/20] e1000: Fix a bug in e1000_probe()
[not found] <1453089161-6697-1-git-send-email-andrew.smirnov@gmail.com>
` (10 preceding siblings ...)
2016-01-18 3:52 ` [PATCH 12/20] e1000: Consolidate Microwire " Andrey Smirnov
@ 2016-01-18 3:52 ` Andrey Smirnov
2016-01-18 3:52 ` [PATCH 14/20] e1000: Remove unnecessary intialization Andrey Smirnov
` (6 subsequent siblings)
18 siblings, 0 replies; 22+ messages in thread
From: Andrey Smirnov @ 2016-01-18 3:52 UTC (permalink / raw)
To: barebox; +Cc: Andrey Smirnov
There are several reasons why that code in e1000_probe had to be
changed:
- It reads from chip variant specific register (present only on
i210) in a chip variant agnostic codepath
- It makes no sense to check for FLUPD bit to make a decision weither
to validate EEPROM or not since its function per datasheet is:
" ... Flash Update.
Writing 1b to this bit causes the content of the internal 4 KB
shadow RAM to be written into one of the first two 4 KB sectors
of the Flash device (Sector 0 or Sector 1). The bit is
self-cleared immediately... "
and it is only through sheer serendipity the defined value for
bitmask for FLUPD is equivalent to bitmask for FLASH_DETECTED bit
which is the bit we actually care about and need to test against
(FLUPD for i210 has a different bitmask)
Fix those problems by replacing the i210 specific check inside of
e1000_validate_eeprom_checksum() with a chip agnostic one and using
correct bitmask.
Signed-off-by: Andrey Smirnov <andrew.smirnov@gmail.com>
---
drivers/net/e1000/e1000.h | 1 +
drivers/net/e1000/eeprom.c | 18 ++++++++++++++++--
drivers/net/e1000/main.c | 3 +--
3 files changed, 18 insertions(+), 4 deletions(-)
diff --git a/drivers/net/e1000/e1000.h b/drivers/net/e1000/e1000.h
index 8ec45a7..92e2100 100644
--- a/drivers/net/e1000/e1000.h
+++ b/drivers/net/e1000/e1000.h
@@ -800,6 +800,7 @@ struct e1000_eeprom_info {
#define E1000_EECD_SELSHAD 0x00020000 /* Select Shadow RAM */
#define E1000_EECD_INITSRAM 0x00040000 /* Initialize Shadow RAM */
#define E1000_EECD_FLUPD 0x00080000 /* Update FLASH */
+#define E1000_EECD_I210_FLASH_DETECTED (1 << 19) /* FLASH detected */
#define E1000_EECD_AUPDEN 0x00100000 /* Enable Autonomous FLASH update */
#define E1000_EECD_SHADV 0x00200000 /* Shadow RAM Data Valid */
#define E1000_EECD_SEC1VAL 0x00400000 /* Sector One Valid */
diff --git a/drivers/net/e1000/eeprom.c b/drivers/net/e1000/eeprom.c
index 87ea82f..4a1c7e6 100644
--- a/drivers/net/e1000/eeprom.c
+++ b/drivers/net/e1000/eeprom.c
@@ -359,8 +359,13 @@ int32_t e1000_init_eeprom_params(struct e1000_hw *hw)
eeprom->use_eerd = true;
break;
case e1000_igb:
- /* i210 has 4k of iNVM mapped as EEPROM */
- eeprom->type = e1000_eeprom_invm;
+ if (eecd & E1000_EECD_I210_FLASH_DETECTED) {
+ eeprom->type = e1000_eeprom_flash;
+ eeprom->word_size = 2048;
+ } else {
+ eeprom->type = e1000_eeprom_invm;
+ }
+
eeprom->use_eerd = true;
break;
default:
@@ -661,6 +666,15 @@ int e1000_validate_eeprom_checksum(struct e1000_hw *hw)
DEBUGFUNC();
+ /*
+ Only the following three 'types' of EEPROM can be expected
+ to have correct EEPROM checksum
+ */
+ if (hw->eeprom.type != e1000_eeprom_spi &&
+ hw->eeprom.type != e1000_eeprom_microwire &&
+ hw->eeprom.type != e1000_eeprom_flash)
+ return 0;
+
/* Read the EEPROM */
if (e1000_read_eeprom(hw, 0, EEPROM_CHECKSUM_REG + 1, buf) < 0) {
dev_err(&hw->edev.dev, "Unable to read EEPROM!\n");
diff --git a/drivers/net/e1000/main.c b/drivers/net/e1000/main.c
index 9791b60..4518be8 100644
--- a/drivers/net/e1000/main.c
+++ b/drivers/net/e1000/main.c
@@ -3558,8 +3558,7 @@ static int e1000_probe(struct pci_dev *pdev, const struct pci_device_id *id)
dev_err(&pdev->dev, "EEPROM is invalid!\n");
return -EINVAL;
}
- if ((E1000_READ_REG(hw, EECD) & E1000_EECD_FLUPD) &&
- e1000_validate_eeprom_checksum(hw))
+ if (e1000_validate_eeprom_checksum(hw))
return -EINVAL;
e1000_get_ethaddr(edev, edev->ethaddr);
--
2.5.0
_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox
^ permalink raw reply [flat|nested] 22+ messages in thread
* [PATCH 14/20] e1000: Remove unnecessary intialization
[not found] <1453089161-6697-1-git-send-email-andrew.smirnov@gmail.com>
` (11 preceding siblings ...)
2016-01-18 3:52 ` [PATCH 13/20] e1000: Fix a bug in e1000_probe() Andrey Smirnov
@ 2016-01-18 3:52 ` Andrey Smirnov
2016-01-18 3:52 ` [PATCH 15/20] e1000: Refactor Flash/EEPROM reading code Andrey Smirnov
` (5 subsequent siblings)
18 siblings, 0 replies; 22+ messages in thread
From: Andrey Smirnov @ 2016-01-18 3:52 UTC (permalink / raw)
To: barebox; +Cc: Andrey Smirnov
We always call e1000_init_eeprom_params() as a part of probing, so
there's no need check if it needs to be called in e1000_read_eeprom().
Signed-off-by: Andrey Smirnov <andrew.smirnov@gmail.com>
---
drivers/net/e1000/eeprom.c | 4 ----
1 file changed, 4 deletions(-)
diff --git a/drivers/net/e1000/eeprom.c b/drivers/net/e1000/eeprom.c
index 4a1c7e6..1f26a87 100644
--- a/drivers/net/e1000/eeprom.c
+++ b/drivers/net/e1000/eeprom.c
@@ -564,10 +564,6 @@ int32_t e1000_read_eeprom(struct e1000_hw *hw, uint16_t offset,
DEBUGFUNC();
- /* If eeprom is not yet detected, do so now */
- if (eeprom->word_size == 0)
- e1000_init_eeprom_params(hw);
-
/* A check for invalid values: offset too large, too many words,
* and not enough words.
*/
--
2.5.0
_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox
^ permalink raw reply [flat|nested] 22+ messages in thread
* [PATCH 15/20] e1000: Refactor Flash/EEPROM reading code
[not found] <1453089161-6697-1-git-send-email-andrew.smirnov@gmail.com>
` (12 preceding siblings ...)
2016-01-18 3:52 ` [PATCH 14/20] e1000: Remove unnecessary intialization Andrey Smirnov
@ 2016-01-18 3:52 ` Andrey Smirnov
2016-01-18 3:52 ` [PATCH 16/20] e1000: Add functions for register polling Andrey Smirnov
` (4 subsequent siblings)
18 siblings, 0 replies; 22+ messages in thread
From: Andrey Smirnov @ 2016-01-18 3:52 UTC (permalink / raw)
To: barebox; +Cc: Andrey Smirnov
Refactor Flash/EEPROM reading code to use vtable with pointers to
small, specialized functions based on the flash class instead of big
monolithic funtions whose behaviour is driven by a number of flags and
variables.
Signed-off-by: Andrey Smirnov <andrew.smirnov@gmail.com>
---
drivers/net/e1000/e1000.h | 9 +-
drivers/net/e1000/eeprom.c | 312 +++++++++++++++++++++++++++------------------
2 files changed, 195 insertions(+), 126 deletions(-)
diff --git a/drivers/net/e1000/e1000.h b/drivers/net/e1000/e1000.h
index 92e2100..291e64d 100644
--- a/drivers/net/e1000/e1000.h
+++ b/drivers/net/e1000/e1000.h
@@ -693,13 +693,20 @@ struct e1000_tx_desc {
#define E1000_82542_FFMT E1000_FFMT
#define E1000_82542_FFVT E1000_FFVT
+struct e1000_hw;
+
struct e1000_eeprom_info {
e1000_eeprom_type type;
uint16_t word_size;
uint16_t opcode_bits;
uint16_t address_bits;
uint16_t delay_usec;
- bool use_eerd;
+
+ int32_t (*acquire) (struct e1000_hw *hw);
+ void (*release) (struct e1000_hw *hw);
+
+ int32_t (*read) (struct e1000_hw *hw, uint16_t offset,
+ uint16_t words, uint16_t *data);
};
#define E1000_EEPROM_SWDPIN0 0x0001 /* SWDPIN 0 EEPROM Value */
diff --git a/drivers/net/e1000/eeprom.c b/drivers/net/e1000/eeprom.c
index 1f26a87..c3677c5 100644
--- a/drivers/net/e1000/eeprom.c
+++ b/drivers/net/e1000/eeprom.c
@@ -5,6 +5,18 @@
#include "e1000.h"
+static void e1000_release_eeprom_spi(struct e1000_hw *hw);
+static int32_t e1000_read_eeprom_spi(struct e1000_hw *hw, uint16_t offset,
+ uint16_t words, uint16_t *data);
+static void e1000_release_eeprom_microwire(struct e1000_hw *hw);
+static int32_t e1000_read_eeprom_microwire(struct e1000_hw *hw, uint16_t offset,
+ uint16_t words, uint16_t *data);
+
+static int32_t e1000_read_eeprom_eerd(struct e1000_hw *hw, uint16_t offset,
+ uint16_t words, uint16_t *data);
+static int32_t e1000_spi_eeprom_ready(struct e1000_hw *hw);
+static void e1000_release_eeprom(struct e1000_hw *hw);
+
/******************************************************************************
@@ -202,28 +214,22 @@ static bool e1000_is_onboard_nvm_eeprom(struct e1000_hw *hw)
return true;
}
-/******************************************************************************
- * Prepares EEPROM for access
- *
- * hw - Struct containing variables accessed by shared code
- *
- * Lowers EEPROM clock. Clears input pin. Sets the chip select pin. This
- * function should be called before issuing a command to the EEPROM.
- *****************************************************************************/
-static int32_t e1000_acquire_eeprom(struct e1000_hw *hw)
+static int32_t
+e1000_acquire_eeprom_spi_microwire_prologue(struct e1000_hw *hw)
{
- struct e1000_eeprom_info *eeprom = &hw->eeprom;
- uint32_t eecd, i = 0;
-
- DEBUGFUNC();
+ uint32_t eecd;
if (e1000_swfw_sync_acquire(hw, E1000_SWFW_EEP_SM))
return -E1000_ERR_SWFW_SYNC;
+
eecd = E1000_READ_REG(hw, EECD);
/* Request EEPROM Access */
- if (hw->mac_type > e1000_82544 && hw->mac_type != e1000_82573 &&
- hw->mac_type != e1000_82574) {
+ if (hw->mac_type > e1000_82544 &&
+ hw->mac_type != e1000_82573 &&
+ hw->mac_type != e1000_82574) {
+ int i = 0;
+
eecd |= E1000_EECD_REQ;
E1000_WRITE_REG(hw, EECD, eecd);
eecd = E1000_READ_REG(hw, EECD);
@@ -241,26 +247,57 @@ static int32_t e1000_acquire_eeprom(struct e1000_hw *hw)
}
}
- /* Setup EEPROM for Read/Write */
+ return E1000_SUCCESS;
+}
+
+static int32_t e1000_acquire_eeprom_spi(struct e1000_hw *hw)
+{
+ int32_t ret;
+ uint32_t eecd;
- if (eeprom->type == e1000_eeprom_microwire) {
- /* Clear SK and DI */
- eecd &= ~(E1000_EECD_DI | E1000_EECD_SK);
- E1000_WRITE_REG(hw, EECD, eecd);
+ ret = e1000_acquire_eeprom_spi_microwire_prologue(hw);
+ if (ret != E1000_SUCCESS)
+ return ret;
- /* Set CS */
- eecd |= E1000_EECD_CS;
- E1000_WRITE_REG(hw, EECD, eecd);
- } else if (eeprom->type == e1000_eeprom_spi) {
- /* Clear SK and CS */
- eecd &= ~(E1000_EECD_CS | E1000_EECD_SK);
- E1000_WRITE_REG(hw, EECD, eecd);
- udelay(1);
- }
+ eecd = E1000_READ_REG(hw, EECD);
+
+ /* Clear SK and CS */
+ eecd &= ~(E1000_EECD_CS | E1000_EECD_SK);
+ E1000_WRITE_REG(hw, EECD, eecd);
+ udelay(1);
return E1000_SUCCESS;
}
+static int32_t e1000_acquire_eeprom_microwire(struct e1000_hw *hw)
+{
+ int ret;
+ uint32_t eecd;
+
+ ret = e1000_acquire_eeprom_spi_microwire_prologue(hw);
+ if (ret != E1000_SUCCESS)
+ return ret;
+
+ eecd = E1000_READ_REG(hw, EECD);
+ /* Clear SK and DI */
+ eecd &= ~(E1000_EECD_DI | E1000_EECD_SK);
+ E1000_WRITE_REG(hw, EECD, eecd);
+
+ /* Set CS */
+ eecd |= E1000_EECD_CS;
+ E1000_WRITE_REG(hw, EECD, eecd);
+
+ return E1000_SUCCESS;
+}
+
+static int32_t e1000_acquire_eeprom(struct e1000_hw *hw)
+{
+ if (hw->eeprom.acquire)
+ return hw->eeprom.acquire(hw);
+ else
+ return E1000_SUCCESS;
+}
+
static void e1000_eeprom_uses_spi(struct e1000_eeprom_info *eeprom,
uint32_t eecd)
{
@@ -273,7 +310,9 @@ static void e1000_eeprom_uses_spi(struct e1000_eeprom_info *eeprom,
eeprom->address_bits = 8;
}
- eeprom->use_eerd = false;
+ eeprom->acquire = e1000_acquire_eeprom_spi;
+ eeprom->release = e1000_release_eeprom_spi;
+ eeprom->read = e1000_read_eeprom_spi;
}
static void e1000_eeprom_uses_microwire(struct e1000_eeprom_info *eeprom,
@@ -289,7 +328,10 @@ static void e1000_eeprom_uses_microwire(struct e1000_eeprom_info *eeprom,
eeprom->word_size = 64;
eeprom->address_bits = 6;
}
- eeprom->use_eerd = false;
+
+ eeprom->acquire = e1000_acquire_eeprom_microwire;
+ eeprom->release = e1000_release_eeprom_microwire;
+ eeprom->read = e1000_read_eeprom_microwire;
}
@@ -343,8 +385,7 @@ int32_t e1000_init_eeprom_params(struct e1000_hw *hw)
if (e1000_is_onboard_nvm_eeprom(hw)) {
e1000_eeprom_uses_spi(eeprom, eecd);
} else {
- eeprom->use_eerd = true;
-
+ eeprom->read = e1000_read_eeprom_eerd;
eeprom->type = e1000_eeprom_flash;
eeprom->word_size = 2048;
@@ -356,7 +397,7 @@ int32_t e1000_init_eeprom_params(struct e1000_hw *hw)
break;
case e1000_80003es2lan:
eeprom->type = e1000_eeprom_spi;
- eeprom->use_eerd = true;
+ eeprom->read = e1000_read_eeprom_eerd;
break;
case e1000_igb:
if (eecd & E1000_EECD_I210_FLASH_DETECTED) {
@@ -366,7 +407,7 @@ int32_t e1000_init_eeprom_params(struct e1000_hw *hw)
eeprom->type = e1000_eeprom_invm;
}
- eeprom->use_eerd = true;
+ eeprom->read = e1000_read_eeprom_eerd;
break;
default:
break;
@@ -465,41 +506,73 @@ static int32_t e1000_read_eeprom_eerd(struct e1000_hw *hw,
return error;
}
-static void e1000_release_eeprom(struct e1000_hw *hw)
+static int32_t e1000_read_eeprom_spi(struct e1000_hw *hw,
+ uint16_t offset,
+ uint16_t words,
+ uint16_t *data)
{
- uint32_t eecd;
+ unsigned int i;
+ uint16_t word_in;
+ uint8_t read_opcode = EEPROM_READ_OPCODE_SPI;
- DEBUGFUNC();
+ if (e1000_spi_eeprom_ready(hw)) {
+ e1000_release_eeprom(hw);
+ return -E1000_ERR_EEPROM;
+ }
- eecd = E1000_READ_REG(hw, EECD);
+ e1000_standby_eeprom(hw);
- if (hw->eeprom.type == e1000_eeprom_spi) {
- eecd |= E1000_EECD_CS; /* Pull CS high */
- eecd &= ~E1000_EECD_SK; /* Lower SCK */
+ /* Some SPI eeproms use the 8th address bit embedded in
+ * the opcode */
+ if ((hw->eeprom.address_bits == 8) && (offset >= 128))
+ read_opcode |= EEPROM_A8_OPCODE_SPI;
- E1000_WRITE_REG(hw, EECD, eecd);
+ /* Send the READ command (opcode + addr) */
+ e1000_shift_out_ee_bits(hw, read_opcode, hw->eeprom.opcode_bits);
+ e1000_shift_out_ee_bits(hw, (uint16_t)(offset * 2),
+ hw->eeprom.address_bits);
- udelay(hw->eeprom.delay_usec);
- } else if (hw->eeprom.type == e1000_eeprom_microwire) {
- /* cleanup eeprom */
+ /* Read the data. The address of the eeprom internally
+ * increments with each byte (spi) being read, saving on the
+ * overhead of eeprom setup and tear-down. The address
+ * counter will roll over if reading beyond the size of
+ * the eeprom, thus allowing the entire memory to be read
+ * starting from any offset. */
+ for (i = 0; i < words; i++) {
+ word_in = e1000_shift_in_ee_bits(hw, 16);
+ data[i] = (word_in >> 8) | (word_in << 8);
+ }
- /* CS on Microwire is active-high */
- eecd &= ~(E1000_EECD_CS | E1000_EECD_DI);
+ return E1000_SUCCESS;
+}
- E1000_WRITE_REG(hw, EECD, eecd);
+static int32_t e1000_read_eeprom_microwire(struct e1000_hw *hw,
+ uint16_t offset,
+ uint16_t words,
+ uint16_t *data)
+{
+ int i;
+ for (i = 0; i < words; i++) {
+ /* Send the READ command (opcode + addr) */
+ e1000_shift_out_ee_bits(hw,
+ EEPROM_READ_OPCODE_MICROWIRE,
+ hw->eeprom.opcode_bits);
+ e1000_shift_out_ee_bits(hw, (uint16_t)(offset + i),
+ hw->eeprom.address_bits);
+
+ /* Read the data. For microwire, each word requires
+ * the overhead of eeprom setup and tear-down. */
+ data[i] = e1000_shift_in_ee_bits(hw, 16);
+ e1000_standby_eeprom(hw);
+ }
- /* Rising edge of clock */
- eecd |= E1000_EECD_SK;
- E1000_WRITE_REG(hw, EECD, eecd);
- E1000_WRITE_FLUSH(hw);
- udelay(hw->eeprom.delay_usec);
+ return E1000_SUCCESS;
+}
- /* Falling edge of clock */
- eecd &= ~E1000_EECD_SK;
- E1000_WRITE_REG(hw, EECD, eecd);
- E1000_WRITE_FLUSH(hw);
- udelay(hw->eeprom.delay_usec);
- }
+static void
+e1000_release_eeprom_spi_microwire_epilogue(struct e1000_hw *hw)
+{
+ uint32_t eecd = E1000_READ_REG(hw, EECD);
/* Stop requesting EEPROM access */
if (hw->mac_type > e1000_82544) {
@@ -507,6 +580,53 @@ static void e1000_release_eeprom(struct e1000_hw *hw)
E1000_WRITE_REG(hw, EECD, eecd);
}
}
+
+static void e1000_release_eeprom_microwire(struct e1000_hw *hw)
+{
+ uint32_t eecd = E1000_READ_REG(hw, EECD);
+
+ /* cleanup eeprom */
+
+ /* CS on Microwire is active-high */
+ eecd &= ~(E1000_EECD_CS | E1000_EECD_DI);
+
+ E1000_WRITE_REG(hw, EECD, eecd);
+
+ /* Rising edge of clock */
+ eecd |= E1000_EECD_SK;
+ E1000_WRITE_REG(hw, EECD, eecd);
+ E1000_WRITE_FLUSH(hw);
+ udelay(hw->eeprom.delay_usec);
+
+ /* Falling edge of clock */
+ eecd &= ~E1000_EECD_SK;
+ E1000_WRITE_REG(hw, EECD, eecd);
+ E1000_WRITE_FLUSH(hw);
+ udelay(hw->eeprom.delay_usec);
+
+
+ e1000_release_eeprom_spi_microwire_epilogue(hw);
+}
+
+static void e1000_release_eeprom_spi(struct e1000_hw *hw)
+{
+ uint32_t eecd = E1000_READ_REG(hw, EECD);
+
+ eecd |= E1000_EECD_CS; /* Pull CS high */
+ eecd &= ~E1000_EECD_SK; /* Lower SCK */
+
+ E1000_WRITE_REG(hw, EECD, eecd);
+ udelay(hw->eeprom.delay_usec);
+
+ e1000_release_eeprom_spi_microwire_epilogue(hw);
+}
+
+static void e1000_release_eeprom(struct e1000_hw *hw)
+{
+ if (hw->eeprom.release)
+ hw->eeprom.release(hw);
+}
+
/******************************************************************************
* Reads a 16 bit word from the EEPROM.
*
@@ -560,7 +680,7 @@ int32_t e1000_read_eeprom(struct e1000_hw *hw, uint16_t offset,
uint16_t words, uint16_t *data)
{
struct e1000_eeprom_info *eeprom = &hw->eeprom;
- uint32_t i = 0;
+ int32_t ret;
DEBUGFUNC();
@@ -575,75 +695,17 @@ int32_t e1000_read_eeprom(struct e1000_hw *hw, uint16_t offset,
return -E1000_ERR_EEPROM;
}
- /* EEPROM's that don't use EERD to read require us to bit-bang the SPI
- * directly. In this case, we need to acquire the EEPROM so that
- * FW or other port software does not interrupt.
- */
- if (e1000_is_onboard_nvm_eeprom(hw) == true &&
- hw->eeprom.use_eerd == false) {
-
- /* Prepare the EEPROM for bit-bang reading */
+ if (eeprom->read) {
if (e1000_acquire_eeprom(hw) != E1000_SUCCESS)
return -E1000_ERR_EEPROM;
- }
- /* Eerd register EEPROM access requires no eeprom aquire/release */
- if (eeprom->use_eerd == true)
- return e1000_read_eeprom_eerd(hw, offset, words, data);
+ ret = eeprom->read(hw, offset, words, data);
+ e1000_release_eeprom(hw);
- /* Set up the SPI or Microwire EEPROM for bit-bang reading. We have
- * acquired the EEPROM at this point, so any returns should relase it */
- if (eeprom->type == e1000_eeprom_spi) {
- uint16_t word_in;
- uint8_t read_opcode = EEPROM_READ_OPCODE_SPI;
-
- if (e1000_spi_eeprom_ready(hw)) {
- e1000_release_eeprom(hw);
- return -E1000_ERR_EEPROM;
- }
-
- e1000_standby_eeprom(hw);
-
- /* Some SPI eeproms use the 8th address bit embedded in
- * the opcode */
- if ((eeprom->address_bits == 8) && (offset >= 128))
- read_opcode |= EEPROM_A8_OPCODE_SPI;
-
- /* Send the READ command (opcode + addr) */
- e1000_shift_out_ee_bits(hw, read_opcode, eeprom->opcode_bits);
- e1000_shift_out_ee_bits(hw, (uint16_t)(offset*2),
- eeprom->address_bits);
-
- /* Read the data. The address of the eeprom internally
- * increments with each byte (spi) being read, saving on the
- * overhead of eeprom setup and tear-down. The address
- * counter will roll over if reading beyond the size of
- * the eeprom, thus allowing the entire memory to be read
- * starting from any offset. */
- for (i = 0; i < words; i++) {
- word_in = e1000_shift_in_ee_bits(hw, 16);
- data[i] = (word_in >> 8) | (word_in << 8);
- }
- } else if (eeprom->type == e1000_eeprom_microwire) {
- for (i = 0; i < words; i++) {
- /* Send the READ command (opcode + addr) */
- e1000_shift_out_ee_bits(hw,
- EEPROM_READ_OPCODE_MICROWIRE,
- eeprom->opcode_bits);
- e1000_shift_out_ee_bits(hw, (uint16_t)(offset + i),
- eeprom->address_bits);
-
- /* Read the data. For microwire, each word requires
- * the overhead of eeprom setup and tear-down. */
- data[i] = e1000_shift_in_ee_bits(hw, 16);
- e1000_standby_eeprom(hw);
- }
+ return ret;
+ } else {
+ return -ENOTSUPP;
}
-
- /* End this read operation */
- e1000_release_eeprom(hw);
-
- return E1000_SUCCESS;
}
/******************************************************************************
--
2.5.0
_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox
^ permalink raw reply [flat|nested] 22+ messages in thread
* [PATCH 16/20] e1000: Add functions for register polling
[not found] <1453089161-6697-1-git-send-email-andrew.smirnov@gmail.com>
` (13 preceding siblings ...)
2016-01-18 3:52 ` [PATCH 15/20] e1000: Refactor Flash/EEPROM reading code Andrey Smirnov
@ 2016-01-18 3:52 ` Andrey Smirnov
2016-01-19 8:21 ` Sascha Hauer
2016-01-18 3:52 ` [PATCH 17/20] e1000: Properly release SW_FW_SYNC semaphore bits Andrey Smirnov
` (3 subsequent siblings)
18 siblings, 1 reply; 22+ messages in thread
From: Andrey Smirnov @ 2016-01-18 3:52 UTC (permalink / raw)
To: barebox; +Cc: Andrey Smirnov
Signed-off-by: Andrey Smirnov <andrew.smirnov@gmail.com>
---
drivers/net/e1000/e1000.h | 19 +++++++++++++++++++
1 file changed, 19 insertions(+)
diff --git a/drivers/net/e1000/e1000.h b/drivers/net/e1000/e1000.h
index 291e64d..5e24758 100644
--- a/drivers/net/e1000/e1000.h
+++ b/drivers/net/e1000/e1000.h
@@ -2176,5 +2176,24 @@ static inline uint32_t e1000_read_reg(struct e1000_hw *hw, uint32_t reg)
}
+static inline int e1000_poll_reg(struct e1000_hw *hw, uint32_t reg,
+ uint32_t mask, uint32_t value,
+ uint64_t timeout)
+{
+ const uint64_t start = get_time_ns();
+
+ do {
+ const uint32_t v = e1000_read_reg(hw, reg);
+
+ if ((v & mask) == value)
+ return 0;
+
+ } while (!is_timeout(start, timeout));
+
+ return -ETIMEDOUT;
+}
+
+#define E1000_POLL_REG(a, reg, mask, value, timeout) \
+ e1000_poll_reg((a), E1000_##reg, (mask), (value), (timeout))
#endif /* _E1000_HW_H_ */
--
2.5.0
_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox
^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: [PATCH 16/20] e1000: Add functions for register polling
2016-01-18 3:52 ` [PATCH 16/20] e1000: Add functions for register polling Andrey Smirnov
@ 2016-01-19 8:21 ` Sascha Hauer
2016-01-19 18:53 ` Andrey Smirnov
0 siblings, 1 reply; 22+ messages in thread
From: Sascha Hauer @ 2016-01-19 8:21 UTC (permalink / raw)
To: Andrey Smirnov; +Cc: barebox
On Sun, Jan 17, 2016 at 07:52:37PM -0800, Andrey Smirnov wrote:
> Signed-off-by: Andrey Smirnov <andrew.smirnov@gmail.com>
> ---
> drivers/net/e1000/e1000.h | 19 +++++++++++++++++++
> 1 file changed, 19 insertions(+)
>
> diff --git a/drivers/net/e1000/e1000.h b/drivers/net/e1000/e1000.h
> index 291e64d..5e24758 100644
> --- a/drivers/net/e1000/e1000.h
> +++ b/drivers/net/e1000/e1000.h
> @@ -2176,5 +2176,24 @@ static inline uint32_t e1000_read_reg(struct e1000_hw *hw, uint32_t reg)
> }
>
>
> +static inline int e1000_poll_reg(struct e1000_hw *hw, uint32_t reg,
> + uint32_t mask, uint32_t value,
> + uint64_t timeout)
We should let the compiler decide whether to inline this or not. Can we
remove the inline?
> +{
> + const uint64_t start = get_time_ns();
> +
> + do {
> + const uint32_t v = e1000_read_reg(hw, reg);
> +
> + if ((v & mask) == value)
> + return 0;
> +
> + } while (!is_timeout(start, timeout));
> +
> + return -ETIMEDOUT;
> +}
> +
> +#define E1000_POLL_REG(a, reg, mask, value, timeout) \
> + e1000_poll_reg((a), E1000_##reg, (mask), (value), (timeout))
Can we drop this define? All it does is to put E1000_ in front of the
register name which could also be done by the caller.
Sascha
--
Pengutronix e.K. | |
Industrial Linux Solutions | http://www.pengutronix.de/ |
Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0 |
Amtsgericht Hildesheim, HRA 2686 | Fax: +49-5121-206917-5555 |
_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox
^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: [PATCH 16/20] e1000: Add functions for register polling
2016-01-19 8:21 ` Sascha Hauer
@ 2016-01-19 18:53 ` Andrey Smirnov
2016-01-20 7:32 ` Sascha Hauer
0 siblings, 1 reply; 22+ messages in thread
From: Andrey Smirnov @ 2016-01-19 18:53 UTC (permalink / raw)
To: Sascha Hauer; +Cc: barebox
On Tue, Jan 19, 2016 at 12:21 AM, Sascha Hauer <s.hauer@pengutronix.de> wrote:
> On Sun, Jan 17, 2016 at 07:52:37PM -0800, Andrey Smirnov wrote:
>> Signed-off-by: Andrey Smirnov <andrew.smirnov@gmail.com>
>> ---
>> drivers/net/e1000/e1000.h | 19 +++++++++++++++++++
>> 1 file changed, 19 insertions(+)
>>
>> diff --git a/drivers/net/e1000/e1000.h b/drivers/net/e1000/e1000.h
>> index 291e64d..5e24758 100644
>> --- a/drivers/net/e1000/e1000.h
>> +++ b/drivers/net/e1000/e1000.h
>> @@ -2176,5 +2176,24 @@ static inline uint32_t e1000_read_reg(struct e1000_hw *hw, uint32_t reg)
>> }
>>
>>
>> +static inline int e1000_poll_reg(struct e1000_hw *hw, uint32_t reg,
>> + uint32_t mask, uint32_t value,
>> + uint64_t timeout)
>
> We should let the compiler decide whether to inline this or not. Can we
> remove the inline?
In general the reason I put "inline" when defining functions in
headers -- that is not to say that it applies in this case -- is
because that tells the compiler that the code for function doesn't
have to put in the object file if no one is using it. Otherwise when
.c that doesn't reference includes .h with static non-inline function
that nobody uses GCC might emit a warning about unused function.
I am not sure if this is true for given the set of flags BB passes to
GCC, so I'll double check and if it's not the case remove the 'inline'
>
>> +{
>> + const uint64_t start = get_time_ns();
>> +
>> + do {
>> + const uint32_t v = e1000_read_reg(hw, reg);
>> +
>> + if ((v & mask) == value)
>> + return 0;
>> +
>> + } while (!is_timeout(start, timeout));
>> +
>> + return -ETIMEDOUT;
>> +}
>> +
>> +#define E1000_POLL_REG(a, reg, mask, value, timeout) \
>> + e1000_poll_reg((a), E1000_##reg, (mask), (value), (timeout))
>
> Can we drop this define? All it does is to put E1000_ in front of the
> register name which could also be done by the caller.
I'd love to do that. How do you feel about getting rid of
E1000_READ_REG and E1000_WRITE_REG?
Andrey
_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox
^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: [PATCH 16/20] e1000: Add functions for register polling
2016-01-19 18:53 ` Andrey Smirnov
@ 2016-01-20 7:32 ` Sascha Hauer
0 siblings, 0 replies; 22+ messages in thread
From: Sascha Hauer @ 2016-01-20 7:32 UTC (permalink / raw)
To: Andrey Smirnov; +Cc: barebox
On Tue, Jan 19, 2016 at 10:53:07AM -0800, Andrey Smirnov wrote:
> On Tue, Jan 19, 2016 at 12:21 AM, Sascha Hauer <s.hauer@pengutronix.de> wrote:
> > On Sun, Jan 17, 2016 at 07:52:37PM -0800, Andrey Smirnov wrote:
> >> Signed-off-by: Andrey Smirnov <andrew.smirnov@gmail.com>
> >> ---
> >> drivers/net/e1000/e1000.h | 19 +++++++++++++++++++
> >> 1 file changed, 19 insertions(+)
> >>
> >> diff --git a/drivers/net/e1000/e1000.h b/drivers/net/e1000/e1000.h
> >> index 291e64d..5e24758 100644
> >> --- a/drivers/net/e1000/e1000.h
> >> +++ b/drivers/net/e1000/e1000.h
> >> @@ -2176,5 +2176,24 @@ static inline uint32_t e1000_read_reg(struct e1000_hw *hw, uint32_t reg)
> >> }
> >>
> >>
> >> +static inline int e1000_poll_reg(struct e1000_hw *hw, uint32_t reg,
> >> + uint32_t mask, uint32_t value,
> >> + uint64_t timeout)
> >
> > We should let the compiler decide whether to inline this or not. Can we
> > remove the inline?
>
> In general the reason I put "inline" when defining functions in
> headers -- that is not to say that it applies in this case -- is
> because that tells the compiler that the code for function doesn't
> have to put in the object file if no one is using it. Otherwise when
> .c that doesn't reference includes .h with static non-inline function
> that nobody uses GCC might emit a warning about unused function.
I didn't realize this function is in the header file. Can we put it in
the C file?
>
> I'd love to do that. How do you feel about getting rid of
> E1000_READ_REG and E1000_WRITE_REG?
Good idea. I'm all in for that.
Sascha
--
Pengutronix e.K. | |
Industrial Linux Solutions | http://www.pengutronix.de/ |
Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0 |
Amtsgericht Hildesheim, HRA 2686 | Fax: +49-5121-206917-5555 |
_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox
^ permalink raw reply [flat|nested] 22+ messages in thread
* [PATCH 17/20] e1000: Properly release SW_FW_SYNC semaphore bits
[not found] <1453089161-6697-1-git-send-email-andrew.smirnov@gmail.com>
` (14 preceding siblings ...)
2016-01-18 3:52 ` [PATCH 16/20] e1000: Add functions for register polling Andrey Smirnov
@ 2016-01-18 3:52 ` Andrey Smirnov
2016-01-18 3:52 ` [PATCH 18/20] e1000: Add EEPROM access locking for i210 Andrey Smirnov
` (2 subsequent siblings)
18 siblings, 0 replies; 22+ messages in thread
From: Andrey Smirnov @ 2016-01-18 3:52 UTC (permalink / raw)
To: barebox; +Cc: Andrey Smirnov
As described in the datasheet Software/Firmware synchronisation bits
are expected to be released by the software after it is done using
it. Add a porper subroutine to do that instead of relying on the
Firmware clearing those bits due to timeout.
Signed-off-by: Andrey Smirnov <andrew.smirnov@gmail.com>
---
drivers/net/e1000/e1000.h | 1 +
drivers/net/e1000/main.c | 30 ++++++++++++++++++++++++++++++
2 files changed, 31 insertions(+)
diff --git a/drivers/net/e1000/e1000.h b/drivers/net/e1000/e1000.h
index 5e24758..cb6c914 100644
--- a/drivers/net/e1000/e1000.h
+++ b/drivers/net/e1000/e1000.h
@@ -2138,6 +2138,7 @@ int32_t e1000_read_eeprom(struct e1000_hw *hw, uint16_t offset,
uint16_t *data);
int32_t e1000_swfw_sync_acquire(struct e1000_hw *hw, uint16_t mask);
+int32_t e1000_swfw_sync_release(struct e1000_hw *hw, uint16_t mask);
struct e1000_fixup_table {
uint32_t orig, fixed;
diff --git a/drivers/net/e1000/main.c b/drivers/net/e1000/main.c
index 4518be8..05d38ac 100644
--- a/drivers/net/e1000/main.c
+++ b/drivers/net/e1000/main.c
@@ -274,6 +274,21 @@ int32_t e1000_swfw_sync_acquire(struct e1000_hw *hw, uint16_t mask)
return E1000_SUCCESS;
}
+int32_t e1000_swfw_sync_release(struct e1000_hw *hw, uint16_t mask)
+{
+ uint32_t swfw_sync;
+
+ if (e1000_get_hw_eeprom_semaphore(hw))
+ return -E1000_ERR_SWFW_SYNC;
+
+ swfw_sync = E1000_READ_REG(hw, SW_FW_SYNC);
+ swfw_sync &= ~mask;
+ E1000_WRITE_REG(hw, SW_FW_SYNC, swfw_sync);
+
+ e1000_put_hw_eeprom_semaphore(hw);
+ return E1000_SUCCESS;
+}
+
static bool e1000_is_second_port(struct e1000_hw *hw)
{
switch (hw->mac_type) {
@@ -1348,6 +1363,11 @@ static int32_t e1000_write_kmrn_reg(struct e1000_hw *hw, uint32_t reg_addr, uint
E1000_WRITE_REG(hw, KUMCTRLSTA, reg_val);
udelay(2);
+ if (e1000_swfw_sync_release(hw, swfw) < 0)
+ dev_warn(hw->dev,
+ "Timeout while releasing SWFW_SYNC bits (0x%08x)\n",
+ swfw);
+
return E1000_SUCCESS;
}
@@ -1375,6 +1395,11 @@ static int32_t e1000_read_kmrn_reg(struct e1000_hw *hw, uint32_t reg_addr, uint1
reg_val = E1000_READ_REG(hw, KUMCTRLSTA);
*data = (uint16_t)reg_val;
+ if (e1000_swfw_sync_release(hw, swfw) < 0)
+ dev_warn(hw->dev,
+ "Timeout while releasing SWFW_SYNC bits (0x%08x)\n",
+ swfw);
+
return E1000_SUCCESS;
}
@@ -2804,6 +2829,11 @@ static int32_t e1000_phy_hw_reset(struct e1000_hw *hw)
if (hw->mac_type >= e1000_82571)
mdelay(10);
+
+ if (e1000_swfw_sync_release(hw, swfw) < 0)
+ dev_warn(hw->dev,
+ "Timeout while releasing SWFW_SYNC bits (0x%08x)\n",
+ swfw);
} else {
/* Read the Extended Device Control Register, assert the PHY_RESET_DIR
* bit to put the PHY into reset. Then, take it out of reset.
--
2.5.0
_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox
^ permalink raw reply [flat|nested] 22+ messages in thread
* [PATCH 18/20] e1000: Add EEPROM access locking for i210
[not found] <1453089161-6697-1-git-send-email-andrew.smirnov@gmail.com>
` (15 preceding siblings ...)
2016-01-18 3:52 ` [PATCH 17/20] e1000: Properly release SW_FW_SYNC semaphore bits Andrey Smirnov
@ 2016-01-18 3:52 ` Andrey Smirnov
2016-01-18 3:52 ` [PATCH 19/20] e1000: Expose i210's external flash as MTD Andrey Smirnov
2016-01-18 3:52 ` [PATCH 20/20] e1000: Expose i210's iNVM as a cdev Andrey Smirnov
18 siblings, 0 replies; 22+ messages in thread
From: Andrey Smirnov @ 2016-01-18 3:52 UTC (permalink / raw)
To: barebox; +Cc: Andrey Smirnov
As per datasheet (section 4.6 p. 147) accessing EEPROM on i210
requires software to hold a corresponding lock bit in SW_FW_SYNC
register.
Signed-off-by: Andrey Smirnov <andrew.smirnov@gmail.com>
---
drivers/net/e1000/eeprom.c | 19 ++++++++++++++++++-
1 file changed, 18 insertions(+), 1 deletion(-)
diff --git a/drivers/net/e1000/eeprom.c b/drivers/net/e1000/eeprom.c
index c3677c5..aca16f7 100644
--- a/drivers/net/e1000/eeprom.c
+++ b/drivers/net/e1000/eeprom.c
@@ -16,7 +16,8 @@ static int32_t e1000_read_eeprom_eerd(struct e1000_hw *hw, uint16_t offset,
uint16_t words, uint16_t *data);
static int32_t e1000_spi_eeprom_ready(struct e1000_hw *hw);
static void e1000_release_eeprom(struct e1000_hw *hw);
-
+static int32_t e1000_acquire_eeprom_flash(struct e1000_hw *hw);
+static void e1000_release_eeprom_flash(struct e1000_hw *hw);
/******************************************************************************
@@ -290,6 +291,11 @@ static int32_t e1000_acquire_eeprom_microwire(struct e1000_hw *hw)
return E1000_SUCCESS;
}
+static int32_t e1000_acquire_eeprom_flash(struct e1000_hw *hw)
+{
+ return e1000_swfw_sync_acquire(hw, E1000_SWFW_EEP_SM);
+}
+
static int32_t e1000_acquire_eeprom(struct e1000_hw *hw)
{
if (hw->eeprom.acquire)
@@ -403,6 +409,9 @@ int32_t e1000_init_eeprom_params(struct e1000_hw *hw)
if (eecd & E1000_EECD_I210_FLASH_DETECTED) {
eeprom->type = e1000_eeprom_flash;
eeprom->word_size = 2048;
+
+ eeprom->acquire = e1000_acquire_eeprom_flash;
+ eeprom->release = e1000_release_eeprom_flash;
} else {
eeprom->type = e1000_eeprom_invm;
}
@@ -621,6 +630,14 @@ static void e1000_release_eeprom_spi(struct e1000_hw *hw)
e1000_release_eeprom_spi_microwire_epilogue(hw);
}
+static void e1000_release_eeprom_flash(struct e1000_hw *hw)
+{
+ if (e1000_swfw_sync_release(hw, E1000_SWFW_EEP_SM) < 0)
+ dev_warn(hw->dev,
+ "Timeout while releasing SWFW_SYNC bits (0x%08x)\n",
+ E1000_SWFW_EEP_SM);
+}
+
static void e1000_release_eeprom(struct e1000_hw *hw)
{
if (hw->eeprom.release)
--
2.5.0
_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox
^ permalink raw reply [flat|nested] 22+ messages in thread
* [PATCH 19/20] e1000: Expose i210's external flash as MTD
[not found] <1453089161-6697-1-git-send-email-andrew.smirnov@gmail.com>
` (16 preceding siblings ...)
2016-01-18 3:52 ` [PATCH 18/20] e1000: Add EEPROM access locking for i210 Andrey Smirnov
@ 2016-01-18 3:52 ` Andrey Smirnov
2016-01-18 3:52 ` [PATCH 20/20] e1000: Expose i210's iNVM as a cdev Andrey Smirnov
18 siblings, 0 replies; 22+ messages in thread
From: Andrey Smirnov @ 2016-01-18 3:52 UTC (permalink / raw)
To: barebox; +Cc: Andrey Smirnov
Add code needed to access SPI-NOR flash attached to i210 as a regular
MTD device.
Signed-off-by: Andrey Smirnov <andrew.smirnov@gmail.com>
---
drivers/net/e1000/e1000.h | 36 +++-
drivers/net/e1000/eeprom.c | 398 ++++++++++++++++++++++++++++++++++++++++++++-
drivers/net/e1000/main.c | 7 +
3 files changed, 438 insertions(+), 3 deletions(-)
diff --git a/drivers/net/e1000/e1000.h b/drivers/net/e1000/e1000.h
index cb6c914..dc38ce1 100644
--- a/drivers/net/e1000/e1000.h
+++ b/drivers/net/e1000/e1000.h
@@ -17,6 +17,7 @@
*/
#include <io.h>
+#include <linux/mtd/mtd.h>
#ifndef _E1000_HW_H_
#define _E1000_HW_H_
@@ -453,8 +454,11 @@ struct e1000_tx_desc {
#define E1000_EEWR 0x0102C /* EEPROM Write Register - RW */
#define E1000_I210_EEWR 0x12018 /* EEPROM Write Register - RW */
#define E1000_FLSWCTL 0x01030 /* FLASH control register */
+#define E1000_I210_FLSWCTL 0x12048 /* FLASH control register */
#define E1000_FLSWDATA 0x01034 /* FLASH data register */
+#define E1000_I210_FLSWDATA 0x1204C /* FLASH data register */
#define E1000_FLSWCNT 0x01038 /* FLASH Access Counter */
+#define E1000_I210_FLSWCNT 0x12050 /* FLASH Access Counter */
#define E1000_FLOP 0x0103C /* FLASH Opcode Register */
#define E1000_ERT 0x02008 /* Early Rx Threshold - RW */
#define E1000_FCRTL 0x02160 /* Flow Control Receive Threshold Low - RW */
@@ -697,7 +701,7 @@ struct e1000_hw;
struct e1000_eeprom_info {
e1000_eeprom_type type;
- uint16_t word_size;
+ size_t word_size;
uint16_t opcode_bits;
uint16_t address_bits;
uint16_t delay_usec;
@@ -811,6 +815,8 @@ struct e1000_eeprom_info {
#define E1000_EECD_AUPDEN 0x00100000 /* Enable Autonomous FLASH update */
#define E1000_EECD_SHADV 0x00200000 /* Shadow RAM Data Valid */
#define E1000_EECD_SEC1VAL 0x00400000 /* Sector One Valid */
+#define E1000_EECD_I210_FLUPD (1 << 23)
+#define E1000_EECD_I210_FLUDONE (1 << 26)
#define E1000_EECD_SECVAL_SHIFT 22
#define E1000_STM_OPCODE 0xDB00
#define E1000_HICR_FW_RESET 0xC0
@@ -2097,6 +2103,28 @@ struct e1000_eeprom_info {
#define E1000_CTRL_EXT_INT_TIMER_CLR 0x20000000 /* Clear Interrupt timers
after IMS clear */
+#define E1000_FLA 0x1201C
+#define E1000_FLA_FL_SIZE_SHIFT 17
+#define E1000_FLA_FL_SIZE_MASK (0b111 << E1000_FLA_FL_SIZE_SHIFT) /* EEprom Size */
+#define E1000_FLA_FL_SIZE_2MB 0b101
+#define E1000_FLA_FL_SIZE_4MB 0b110
+#define E1000_FLA_FL_SIZE_8MB 0b111
+
+
+#define E1000_FLSWCTL_ADDR(a) ((a) & 0x00FFFFFF)
+#define E1000_FLSWCTL_CMD_READ 0b0000
+#define E1000_FLSWCTL_CMD_WRITE 0b0001
+#define E1000_FLSWCTL_CMD_ERASE_SECTOR 0b0010
+#define E1000_FLSWCTL_CMD_ERASE_DEVICE 0b0011
+#define E1000_FLSWCTL_CMD_(c) ((0b1111 & (c)) << 24)
+#define E1000_FLSWCTL_CMD(c) E1000_FLSWCTL_CMD_(E1000_FLSWCTL_CMD_##c)
+
+#define E1000_FLSWCTL_CMD_ADDR_MASK 0x0FFFFFFF
+
+#define E1000_FLSWCTL_CMDV (1 << 28)
+#define E1000_FLSWCTL_FLBUSY (1 << 29)
+#define E1000_FLSWCTL_DONE (1 << 30)
+#define E1000_FLSWCTL_GLDONE (1 << 31)
struct e1000_hw {
struct eth_device edev;
@@ -2112,6 +2140,7 @@ struct e1000_hw {
e1000_media_type media_type;
e1000_fc_type fc;
struct e1000_eeprom_info eeprom;
+ struct mtd_info mtd;
uint32_t phy_id;
uint32_t phy_revision;
uint32_t original_fc;
@@ -2150,6 +2179,9 @@ static inline uint32_t e1000_true_offset(struct e1000_hw *hw, uint32_t reg)
unsigned int i;
const struct e1000_fixup_table fixup_table[] = {
+ { E1000_FLSWCTL, E1000_I210_FLSWCTL },
+ { E1000_FLSWDATA, E1000_I210_FLSWDATA },
+ { E1000_FLSWCNT, E1000_I210_FLSWCNT },
{ E1000_EEWR, E1000_I210_EEWR },
{ E1000_PHY_CTRL, E1000_I210_PHY_CTRL },
{ E1000_EEMNGCTL, E1000_I210_EEMNGCTL },
@@ -2197,4 +2229,6 @@ static inline int e1000_poll_reg(struct e1000_hw *hw, uint32_t reg,
#define E1000_POLL_REG(a, reg, mask, value, timeout) \
e1000_poll_reg((a), E1000_##reg, (mask), (value), (timeout))
+int e1000_register_eeprom(struct e1000_hw *hw);
+
#endif /* _E1000_HW_H_ */
diff --git a/drivers/net/e1000/eeprom.c b/drivers/net/e1000/eeprom.c
index aca16f7..4ea7128 100644
--- a/drivers/net/e1000/eeprom.c
+++ b/drivers/net/e1000/eeprom.c
@@ -2,6 +2,8 @@
#include <init.h>
#include <net.h>
#include <malloc.h>
+#include <linux/math64.h>
+#include <linux/sizes.h>
#include "e1000.h"
@@ -407,9 +409,29 @@ int32_t e1000_init_eeprom_params(struct e1000_hw *hw)
break;
case e1000_igb:
if (eecd & E1000_EECD_I210_FLASH_DETECTED) {
- eeprom->type = e1000_eeprom_flash;
- eeprom->word_size = 2048;
+ uint32_t fla;
+
+ fla = E1000_READ_REG(hw, FLA);
+ fla &= E1000_FLA_FL_SIZE_MASK;
+ fla >>= E1000_FLA_FL_SIZE_SHIFT;
+
+ switch (fla) {
+ case E1000_FLA_FL_SIZE_8MB:
+ eeprom->word_size = SZ_8M / 2;
+ break;
+ case E1000_FLA_FL_SIZE_4MB:
+ eeprom->word_size = SZ_4M / 2;
+ break;
+ case E1000_FLA_FL_SIZE_2MB:
+ eeprom->word_size = SZ_2M / 2;
+ break;
+ default:
+ eeprom->word_size = 2048;
+ dev_info(hw->dev, "Unprogrammed Flash detected, "
+ "limiting access to first 4KB\n");
+ }
+ eeprom->type = e1000_eeprom_flash;
eeprom->acquire = e1000_acquire_eeprom_flash;
eeprom->release = e1000_release_eeprom_flash;
} else {
@@ -686,6 +708,257 @@ static int32_t e1000_spi_eeprom_ready(struct e1000_hw *hw)
return E1000_SUCCESS;
}
+static int e1000_flash_mode_wait_for_idle(struct e1000_hw *hw)
+{
+ /* Strictly speaking we need to poll FLSWCTL.DONE only if we
+ * are executing this code after a reset event, but it
+ * shouldn't hurt to do this everytime, besided we need to
+ * poll got FLSWCTL.GLDONE to make sure that back to back
+ * calls to that function work correctly, since we finish
+ * execution by polling only FLSWCTL.DONE */
+
+ const int ret = E1000_POLL_REG(hw, FLSWCTL,
+ E1000_FLSWCTL_DONE | E1000_FLSWCTL_GLDONE,
+ E1000_FLSWCTL_DONE | E1000_FLSWCTL_GLDONE,
+ SECOND);
+ if (ret < 0)
+ dev_err(hw->dev,
+ "Timeout waiting for FLSWCTL.DONE to be set\n");
+ return ret;
+}
+
+static int e1000_flash_mode_check_command_valid(struct e1000_hw *hw)
+{
+ const uint32_t flswctl = E1000_READ_REG(hw, FLSWCTL);
+ if (!(flswctl & E1000_FLSWCTL_CMDV)) {
+ dev_err(hw->dev, "FLSWCTL.CMDV was cleared");
+ return -EIO;
+ }
+
+ return E1000_SUCCESS;
+}
+
+#define E1000_FLASH_CMD(hw, cmd, offset) \
+ do { \
+ uint32_t ___flswctl = E1000_READ_REG(hw, FLSWCTL); \
+ ___flswctl &= ~E1000_FLSWCTL_CMD_ADDR_MASK; \
+ ___flswctl |= E1000_FLSWCTL_CMD(cmd) | E1000_FLSWCTL_ADDR(offset); \
+ E1000_WRITE_REG(hw, FLSWCTL, ___flswctl); \
+ } while (0)
+
+static int e1000_flash_mode_read_chunk(struct e1000_hw *hw, loff_t offset,
+ size_t size, void *data)
+{
+ int ret;
+ size_t chunk, residue = size;
+ uint32_t flswdata;
+
+ DEBUGFUNC();
+
+ if (size > SZ_4K ||
+ E1000_FLSWCTL_ADDR(offset) != offset)
+ return -EINVAL;
+
+ ret = e1000_flash_mode_wait_for_idle(hw);
+ if (ret < 0)
+ return ret;
+
+ E1000_WRITE_REG(hw, FLSWCNT, size);
+ E1000_FLASH_CMD(hw, READ, offset);
+
+ do {
+ ret = e1000_flash_mode_check_command_valid(hw);
+ if (ret < 0)
+ return -EIO;
+
+ chunk = min(sizeof(flswdata), residue);
+
+ ret = E1000_POLL_REG(hw, FLSWCTL,
+ E1000_FLSWCTL_DONE, E1000_FLSWCTL_DONE,
+ SECOND);
+ if (ret < 0) {
+ dev_err(hw->dev,
+ "Timeout waiting for FLSWCTL.DONE to be set\n");
+ return ret;
+ }
+
+ flswdata = E1000_READ_REG(hw, FLSWDATA);
+ /*
+ * Readl does le32_to_cpu, so we need to undo that
+ */
+ flswdata = cpu_to_le32(flswdata);
+ memcpy(data, &flswdata, chunk);
+
+ data += chunk;
+ residue -= chunk;
+ } while (residue);
+
+ return E1000_SUCCESS;
+}
+
+static int e1000_flash_mode_write_chunk(struct e1000_hw *hw, loff_t offset,
+ size_t size, const void *data)
+{
+ int ret;
+ size_t chunk, residue = size;
+ uint32_t flswdata;
+
+ if (size > 256 ||
+ E1000_FLSWCTL_ADDR(offset) != offset)
+ return -EINVAL;
+
+ ret = e1000_flash_mode_wait_for_idle(hw);
+ if (ret < 0)
+ return ret;
+
+
+ E1000_WRITE_REG(hw, FLSWCNT, size);
+ E1000_FLASH_CMD(hw, WRITE, offset);
+
+ do {
+ chunk = min(sizeof(flswdata), residue);
+ memcpy(&flswdata, data, chunk);
+ /*
+ * writel does cpu_to_le32, so we do the inverse in
+ * order to account for that
+ */
+ flswdata = le32_to_cpu(flswdata);
+ E1000_WRITE_REG(hw, FLSWDATA, flswdata);
+
+ ret = e1000_flash_mode_check_command_valid(hw);
+ if (ret < 0)
+ return -EIO;
+
+ ret = E1000_POLL_REG(hw, FLSWCTL,
+ E1000_FLSWCTL_DONE, E1000_FLSWCTL_DONE,
+ SECOND);
+ if (ret < 0) {
+ dev_err(hw->dev,
+ "Timeout waiting for FLSWCTL.DONE to be set\n");
+ return ret;
+ }
+
+ data += chunk;
+ residue -= chunk;
+
+ } while (residue);
+
+ return E1000_SUCCESS;
+}
+
+
+static int e1000_flash_mode_erase_chunk(struct e1000_hw *hw, loff_t offset,
+ size_t size)
+{
+ int ret;
+
+ ret = e1000_flash_mode_wait_for_idle(hw);
+ if (ret < 0)
+ return ret;
+
+ if (!size && !offset)
+ E1000_FLASH_CMD(hw, ERASE_DEVICE, 0);
+ else
+ E1000_FLASH_CMD(hw, ERASE_SECTOR, offset);
+
+ ret = e1000_flash_mode_check_command_valid(hw);
+ if (ret < 0)
+ return -EIO;
+
+ ret = E1000_POLL_REG(hw, FLSWCTL,
+ E1000_FLSWCTL_DONE | E1000_FLSWCTL_FLBUSY,
+ E1000_FLSWCTL_DONE,
+ SECOND);
+ if (ret < 0) {
+ dev_err(hw->dev,
+ "Timeout waiting for FLSWCTL.DONE to be set\n");
+ return ret;
+ }
+
+ return E1000_SUCCESS;
+}
+
+enum {
+ E1000_FLASH_MODE_OP_READ = 0,
+ E1000_FLASH_MODE_OP_WRITE = 1,
+ E1000_FLASH_MODE_OP_ERASE = 2,
+};
+
+
+static int e1000_flash_mode_io(struct e1000_hw *hw, int op, size_t granularity,
+ loff_t offset, size_t size, void *data)
+{
+ int ret;
+ size_t residue = size;
+
+ do {
+ const size_t chunk = min(granularity, residue);
+
+ switch (op) {
+ case E1000_FLASH_MODE_OP_READ:
+ ret = e1000_flash_mode_read_chunk(hw, offset,
+ chunk, data);
+ break;
+ case E1000_FLASH_MODE_OP_WRITE:
+ ret = e1000_flash_mode_write_chunk(hw, offset,
+ chunk, data);
+ break;
+ case E1000_FLASH_MODE_OP_ERASE:
+ ret = e1000_flash_mode_erase_chunk(hw, offset,
+ chunk);
+ break;
+ default:
+ return -ENOTSUPP;
+ }
+
+ if (ret < 0)
+ return ret;
+
+ offset += chunk;
+ residue -= chunk;
+ data += chunk;
+ } while (residue);
+
+ return E1000_SUCCESS;
+}
+
+
+static int e1000_flash_mode_read(struct e1000_hw *hw, loff_t offset,
+ size_t size, void *data)
+{
+ return e1000_flash_mode_io(hw,
+ E1000_FLASH_MODE_OP_READ, SZ_4K,
+ offset, size, data);
+}
+
+static int e1000_flash_mode_write(struct e1000_hw *hw, loff_t offset,
+ size_t size, const void *data)
+{
+ int ret;
+
+ ret = e1000_flash_mode_io(hw,
+ E1000_FLASH_MODE_OP_WRITE, 256,
+ offset, size, (void *)data);
+ if (ret < 0)
+ return ret;
+
+ ret = E1000_POLL_REG(hw, FLSWCTL, E1000_FLSWCTL_FLBUSY,
+ 0, SECOND);
+ if (ret < 0)
+ dev_err(hw->dev, "Timout while waiting for FLSWCTL.FLBUSY\n");
+
+ return ret;
+}
+
+static int e1000_flash_mode_erase(struct e1000_hw *hw, loff_t offset,
+ size_t size)
+{
+ return e1000_flash_mode_io(hw,
+ E1000_FLASH_MODE_OP_ERASE, SZ_4K,
+ offset, size, NULL);
+}
+
+
/******************************************************************************
* Reads a 16 bit word from the EEPROM.
*
@@ -774,3 +1047,124 @@ int e1000_validate_eeprom_checksum(struct e1000_hw *hw)
return -E1000_ERR_EEPROM;
}
+
+static int e1000_mtd_read_or_write(bool read,
+ struct mtd_info *mtd, loff_t off, size_t len,
+ size_t *retlen, u_char *buf)
+{
+ int ret;
+ struct e1000_hw *hw = container_of(mtd, struct e1000_hw, mtd);
+
+ DEBUGFUNC();
+
+ if (e1000_acquire_eeprom(hw) == E1000_SUCCESS) {
+ if (read)
+ ret = e1000_flash_mode_read(hw, off,
+ len, buf);
+ else
+ ret = e1000_flash_mode_write(hw, off,
+ len, buf);
+ if (ret == E1000_SUCCESS)
+ *retlen = len;
+
+ e1000_release_eeprom(hw);
+ } else {
+ ret = -E1000_ERR_EEPROM;
+ }
+
+ return ret;
+
+}
+
+static int e1000_mtd_read(struct mtd_info *mtd, loff_t from, size_t len,
+ size_t *retlen, u_char *buf)
+{
+ return e1000_mtd_read_or_write(true,
+ mtd, from, len, retlen, buf);
+}
+
+static int e1000_mtd_write(struct mtd_info *mtd, loff_t to, size_t len,
+ size_t *retlen, const u_char *buf)
+{
+ return e1000_mtd_read_or_write(false,
+ mtd, to, len, retlen, (u_char *)buf);
+}
+
+static int e1000_mtd_erase(struct mtd_info *mtd, struct erase_info *instr)
+{
+ uint32_t rem;
+ struct e1000_hw *hw = container_of(mtd, struct e1000_hw, mtd);
+ int ret;
+
+ div_u64_rem(instr->len, mtd->erasesize, &rem);
+ if (rem)
+ return -EINVAL;
+
+ ret = e1000_acquire_eeprom(hw);
+ if (ret != E1000_SUCCESS)
+ goto fail;
+
+ /*
+ * If mtd->size is 4096 it means we are dealing with
+ * unprogrammed flash and we don't really know its size to
+ * make an informed decision wheither to erase the whole chip or
+ * just a number of its sectors
+ */
+ if (mtd->size > SZ_4K &&
+ instr->len == mtd->size)
+ ret = e1000_flash_mode_erase(hw, 0, 0);
+ else
+ ret = e1000_flash_mode_erase(hw,
+ instr->addr, instr->len);
+
+ e1000_release_eeprom(hw);
+
+ if (ret < 0)
+ goto fail;
+
+ instr->state = MTD_ERASE_DONE;
+ mtd_erase_callback(instr);
+
+ return 0;
+
+fail:
+ instr->state = MTD_ERASE_FAILED;
+ return ret;
+}
+
+int e1000_register_eeprom(struct e1000_hw *hw)
+{
+ int ret = E1000_SUCCESS;
+ struct e1000_eeprom_info *eeprom = &hw->eeprom;
+
+ switch (eeprom->type) {
+ case e1000_eeprom_flash:
+ if (hw->mac_type != e1000_igb)
+ break;
+
+ hw->mtd.parent = hw->dev;
+ hw->mtd.read = e1000_mtd_read;
+ hw->mtd.write = e1000_mtd_write;
+ hw->mtd.erase = e1000_mtd_erase;
+ hw->mtd.size = eeprom->word_size * 2;
+ hw->mtd.writesize = 1;
+ hw->mtd.subpage_sft = 0;
+
+ hw->mtd.eraseregions = xzalloc(sizeof(struct mtd_erase_region_info));
+ hw->mtd.erasesize = SZ_4K;
+ hw->mtd.eraseregions[0].erasesize = SZ_4K;
+ hw->mtd.eraseregions[0].numblocks = hw->mtd.size / SZ_4K;
+ hw->mtd.numeraseregions = 1;
+
+ hw->mtd.flags = MTD_CAP_NORFLASH;
+ hw->mtd.type = MTD_NORFLASH;
+
+ ret = add_mtd_device(&hw->mtd, "e1000-nor",
+ DEVICE_ID_DYNAMIC);
+ break;
+ default:
+ break;
+ }
+
+ return ret;
+}
diff --git a/drivers/net/e1000/main.c b/drivers/net/e1000/main.c
index 05d38ac..473d121 100644
--- a/drivers/net/e1000/main.c
+++ b/drivers/net/e1000/main.c
@@ -3588,6 +3588,13 @@ static int e1000_probe(struct pci_dev *pdev, const struct pci_device_id *id)
dev_err(&pdev->dev, "EEPROM is invalid!\n");
return -EINVAL;
}
+
+ ret = e1000_register_eeprom(hw);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "failed to register EEPROM devices!\n");
+ return ret;
+ }
+
if (e1000_validate_eeprom_checksum(hw))
return -EINVAL;
--
2.5.0
_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox
^ permalink raw reply [flat|nested] 22+ messages in thread
* [PATCH 20/20] e1000: Expose i210's iNVM as a cdev
[not found] <1453089161-6697-1-git-send-email-andrew.smirnov@gmail.com>
` (17 preceding siblings ...)
2016-01-18 3:52 ` [PATCH 19/20] e1000: Expose i210's external flash as MTD Andrey Smirnov
@ 2016-01-18 3:52 ` Andrey Smirnov
18 siblings, 0 replies; 22+ messages in thread
From: Andrey Smirnov @ 2016-01-18 3:52 UTC (permalink / raw)
To: barebox; +Cc: Andrey Smirnov
Add code needed to expose iNVM memory on the chip as a cdev. The
driver also registers a dummy "invm" device that exposes "locked"
property which is used to implement iNMV line locking feature.
Signed-off-by: Andrey Smirnov <andrew.smirnov@gmail.com>
---
drivers/net/e1000/e1000.h | 35 ++++++
drivers/net/e1000/eeprom.c | 303 +++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 338 insertions(+)
diff --git a/drivers/net/e1000/e1000.h b/drivers/net/e1000/e1000.h
index dc38ce1..a47f808 100644
--- a/drivers/net/e1000/e1000.h
+++ b/drivers/net/e1000/e1000.h
@@ -1990,6 +1990,11 @@ struct e1000_eeprom_info {
#define ICH_FLASH_LINEAR_ADDR_MASK 0x00FFFFFF
#define E1000_SW_FW_SYNC 0x05B5C /* Software-Firmware Synchronization - RW */
+#define E1000_PCIEMISC 0x05BB8
+#define E1000_PCIEMISC_DMA_IDLE (1 << 9)
+#define E1000_PCIEMISC_RESERVED_MASK (~(E1000_PCIEMISC_DMA_IDLE))
+#define E1000_PCIEMISC_RESERVED_PATTERN1 0x8A
+#define E1000_PCIEMISC_RESERVED_PATTERN2 (0x122 << 10)
/* SPI EEPROM Status Register */
#define EEPROM_STATUS_RDY_SPI 0x01
@@ -2126,6 +2131,29 @@ struct e1000_eeprom_info {
#define E1000_FLSWCTL_DONE (1 << 30)
#define E1000_FLSWCTL_GLDONE (1 << 31)
+
+#define E1000_INVM_TEST(n) (0x122A0 + 4 * (n))
+#define E1000_INVM_DATA_(n) (0x12120 + 4 * (n))
+#if 0
+#define E1000_INVM_DATA(n) E1000_INVM_TEST(n)
+#else
+#define E1000_INVM_DATA(n) E1000_INVM_DATA_(n)
+#endif
+
+#define E1000_INVM_LOCK(n) (0x12220 + 4 * (n))
+#define E1000_INVM_LOCK_BIT (1 << 0)
+
+#define E1000_INVM_PROTECT 0x12324
+#define E1000_INVM_PROTECT_CODE (0xABACADA << 4)
+#define E1000_INVM_PROTECT_BUSY (1 << 2)
+#define E1000_INVM_PROTECT_WRITE_ERROR (1 << 1)
+#define E1000_INVM_PROTECT_ALLOW_WRITE (1 << 0)
+
+#define E1000_INVM_DATA_MAX_N 63
+
+#define E1000_EEMNGCTL_CFG_DONE (1 << 18)
+
+
struct e1000_hw {
struct eth_device edev;
@@ -2141,6 +2169,13 @@ struct e1000_hw {
e1000_fc_type fc;
struct e1000_eeprom_info eeprom;
struct mtd_info mtd;
+
+ struct {
+ struct cdev cdev;
+ struct device_d dev;
+ int line;
+ } invm;
+
uint32_t phy_id;
uint32_t phy_revision;
uint32_t original_fc;
diff --git a/drivers/net/e1000/eeprom.c b/drivers/net/e1000/eeprom.c
index 4ea7128..1f7d630 100644
--- a/drivers/net/e1000/eeprom.c
+++ b/drivers/net/e1000/eeprom.c
@@ -1132,12 +1132,315 @@ fail:
return ret;
}
+
+static ssize_t e1000_invm_cdev_read(struct cdev *cdev, void *buf,
+ size_t count, loff_t offset, unsigned long flags)
+{
+ uint8_t n, bnr;
+ uint32_t line;
+ size_t chunk, residue = count;
+ struct e1000_hw *hw = container_of(cdev, struct e1000_hw, invm.cdev);
+
+ n = offset / sizeof(line);
+ if (n > E1000_INVM_DATA_MAX_N)
+ return -EINVAL;
+
+ bnr = offset % sizeof(line);
+ if (bnr) {
+ /*
+ * if bnr in not zero it means we have a non 4-byte
+ * aligned start and need to do a partial read
+ */
+ const uint8_t *bptr;
+
+ bptr = (uint8_t *)&line + bnr;
+ chunk = min(bnr - sizeof(line), count);
+ line = e1000_read_reg(hw, E1000_INVM_DATA(n));
+ line = cpu_to_le32(line); /* to account for readl */
+ memcpy(buf, bptr, chunk);
+
+ goto start_adjusted;
+ }
+
+ do {
+ if (n > E1000_INVM_DATA_MAX_N)
+ return -EINVAL;
+
+ chunk = min(sizeof(line), residue);
+ line = e1000_read_reg(hw, E1000_INVM_DATA(n));
+ line = cpu_to_le32(line); /* to account for readl */
+
+ /*
+ * by using memcpy in conjunction with min should get
+ * dangling tail reads as well as aligned reads
+ */
+ memcpy(buf, &line, chunk);
+
+ start_adjusted:
+ residue -= chunk;
+ buf += chunk;
+ n++;
+ } while (residue);
+
+ return count;
+}
+
+static int e1000_invm_program(struct e1000_hw *hw, u32 offset, u32 value,
+ unsigned int delay)
+{
+ int retries = 400;
+ do {
+ if ((e1000_read_reg(hw, offset) & value) == value)
+ return E1000_SUCCESS;
+
+ e1000_write_reg(hw, offset, value);
+
+ if (delay) {
+ udelay(delay);
+ } else {
+ int ret;
+
+ if (E1000_READ_REG(hw, INVM_PROTECT) &
+ E1000_INVM_PROTECT_WRITE_ERROR) {
+ dev_err(hw->dev, "Error while writing to %x\n", offset);
+ return -EIO;
+ }
+
+ ret = E1000_POLL_REG(hw, INVM_PROTECT,
+ E1000_INVM_PROTECT_BUSY,
+ 0, SECOND);
+ if (ret < 0) {
+ dev_err(hw->dev,
+ "Timeout while waiting for INVM_PROTECT.BUSY\n");
+ return ret;
+ }
+ }
+ } while (retries--);
+
+ return -ETIMEDOUT;
+}
+
+static int e1000_invm_set_lock(struct param_d *param, void *priv)
+{
+ struct e1000_hw *hw = priv;
+
+ if (hw->invm.line > 31)
+ return -EINVAL;
+
+ return e1000_invm_program(hw,
+ E1000_INVM_LOCK(hw->invm.line),
+ E1000_INVM_LOCK_BIT,
+ 10);
+}
+
+static int e1000_invm_unlock(struct e1000_hw *hw)
+{
+ E1000_WRITE_REG(hw, INVM_PROTECT, E1000_INVM_PROTECT_CODE);
+ /*
+ If we were successful at unlocking iNVM for programming we
+ should see ALLOW_WRITE bit toggle to 1
+ */
+ if (!(E1000_READ_REG(hw, INVM_PROTECT) &
+ E1000_INVM_PROTECT_ALLOW_WRITE))
+ return -EIO;
+ else
+ return E1000_SUCCESS;
+}
+
+static void e1000_invm_lock(struct e1000_hw *hw)
+{
+ E1000_WRITE_REG(hw, INVM_PROTECT, 0);
+}
+
+static int e1000_invm_write_prepare(struct e1000_hw *hw)
+{
+ int ret;
+ /*
+ This needs to be done accorging to the datasheet p. 541 and
+ p. 79
+ */
+ E1000_WRITE_REG(hw, PCIEMISC,
+ E1000_PCIEMISC_RESERVED_PATTERN1 |
+ E1000_PCIEMISC_DMA_IDLE |
+ E1000_PCIEMISC_RESERVED_PATTERN2);
+
+ /*
+ Needed for programming iNVM on devices with Flash with valid
+ contents attached
+ */
+ ret = E1000_POLL_REG(hw, EEMNGCTL,
+ E1000_EEMNGCTL_CFG_DONE,
+ E1000_EEMNGCTL_CFG_DONE, SECOND);
+ if (ret < 0) {
+ dev_err(hw->dev,
+ "Timeout while waiting for EEMNGCTL.CFG_DONE\n");
+ return ret;
+ }
+
+ udelay(15);
+
+ return E1000_SUCCESS;
+}
+
+static ssize_t e1000_invm_cdev_write(struct cdev *cdev, const void *buf,
+ size_t count, loff_t offset, unsigned long flags)
+{
+ int ret;
+ uint8_t n, bnr;
+ uint32_t line;
+ size_t chunk, residue = count;
+ struct e1000_hw *hw = container_of(cdev, struct e1000_hw, invm.cdev);
+
+ ret = e1000_invm_write_prepare(hw);
+ if (ret < 0)
+ return ret;
+
+ ret = e1000_invm_unlock(hw);
+ if (ret < 0)
+ goto exit;
+
+ n = offset / sizeof(line);
+ if (n > E1000_INVM_DATA_MAX_N) {
+ ret = -EINVAL;
+ goto exit;
+ }
+
+ bnr = offset % sizeof(line);
+ if (bnr) {
+ uint8_t *bptr;
+ /*
+ * if bnr in not zero it means we have a non 4-byte
+ * aligned start and need to do a read-modify-write
+ * sequence
+ */
+
+ /* Read */
+ line = e1000_read_reg(hw, E1000_INVM_DATA(n));
+
+ /* Modify */
+ /*
+ * We need to ensure that line is LE32 in order for
+ * memcpy to copy byte from least significant to most
+ * significant, since that's how i210 will write the
+ * 32-bit word out to OTP
+ */
+ line = cpu_to_le32(line);
+ bptr = (uint8_t *)&line + bnr;
+ chunk = min(sizeof(line) - bnr, count);
+ memcpy(bptr, buf, chunk);
+ line = le32_to_cpu(line);
+
+ /* Jumping inside of the loop to take care of the
+ * Write */
+ goto start_adjusted;
+ }
+
+ do {
+ if (n > E1000_INVM_DATA_MAX_N) {
+ ret = -EINVAL;
+ goto exit;
+ }
+
+ chunk = min(sizeof(line), residue);
+ if (chunk != sizeof(line)) {
+ /*
+ * If chunk is smaller that sizeof(line), which
+ * should be 4 bytes, we have a "dangling"
+ * chunk and we should read the unchanged
+ * portion of the 4-byte word from iNVM and do
+ * a read-modify-write sequence
+ */
+ line = e1000_read_reg(hw, E1000_INVM_DATA(n));
+ }
+
+ line = cpu_to_le32(line);
+ memcpy(&line, buf, chunk);
+ line = le32_to_cpu(line);
+
+ start_adjusted:
+ /*
+ * iNVM is organized in 32 64-bit lines and each of
+ * those lines can be locked to prevent any further
+ * modification, so for every i-th 32-bit word we need
+ * to check INVM_LINE[i/2] register to see if that word
+ * can be modified
+ */
+ if (e1000_read_reg(hw, E1000_INVM_LOCK(n / 2)) &
+ E1000_INVM_LOCK_BIT) {
+ dev_err(hw->dev, "line %d is locked\n", n / 2);
+ ret = -EIO;
+ goto exit;
+ }
+
+ ret = e1000_invm_program(hw,
+ E1000_INVM_DATA(n),
+ line,
+ 0);
+ if (ret < 0)
+ goto exit;
+
+ residue -= chunk;
+ buf += chunk;
+ n++;
+ } while (residue);
+
+ ret = E1000_SUCCESS;
+exit:
+ e1000_invm_lock(hw);
+ return ret;
+}
+
+static struct file_operations e1000_invm_ops = {
+ .read = e1000_invm_cdev_read,
+ .write = e1000_invm_cdev_write,
+ .lseek = dev_lseek_default,
+};
+
int e1000_register_eeprom(struct e1000_hw *hw)
{
int ret = E1000_SUCCESS;
+ u16 word;
+ struct param_d *p;
+
struct e1000_eeprom_info *eeprom = &hw->eeprom;
switch (eeprom->type) {
+ case e1000_eeprom_invm:
+ 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");
+
+ hw->invm.cdev.dev = hw->dev;
+ hw->invm.cdev.ops = &e1000_invm_ops;
+ hw->invm.cdev.priv = hw;
+ hw->invm.cdev.name = xasprintf("e1000-invm%d", hw->dev->id);
+ hw->invm.cdev.size = 32 * E1000_INVM_DATA_MAX_N;
+
+ ret = devfs_create(&hw->invm.cdev);
+ if (ret < 0)
+ break;
+
+ strcpy(hw->invm.dev.name, "invm");
+ hw->invm.dev.parent = hw->dev;
+ ret = register_device(&hw->invm.dev);
+ if (ret < 0) {
+ devfs_remove(&hw->invm.cdev);
+ break;
+ }
+
+ p = dev_add_param_int(&hw->invm.dev, "lock", e1000_invm_set_lock,
+ NULL, &hw->invm.line, "%u", hw);
+ if (IS_ERR(p)) {
+ unregister_device(&hw->invm.dev);
+ devfs_remove(&hw->invm.cdev);
+ break;
+ }
+
+ break;
+
case e1000_eeprom_flash:
if (hw->mac_type != e1000_igb)
break;
--
2.5.0
_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox
^ permalink raw reply [flat|nested] 22+ messages in thread