diff options
author | Andrey Smirnov <andrew.smirnov@gmail.com> | 2016-06-01 21:58:47 -0700 |
---|---|---|
committer | Sascha Hauer <s.hauer@pengutronix.de> | 2016-06-03 09:14:14 +0200 |
commit | 741cdaf506f9609998418e54396796a4db4ddb3c (patch) | |
tree | 762bf8b7b506252dcfbbd5f4d32c5786da98d3c5 /drivers/net | |
parent | 2bac1677692e9de0b6bf53ca1cfae6a2a83b7857 (diff) | |
download | barebox-741cdaf506f9609998418e54396796a4db4ddb3c.tar.gz barebox-741cdaf506f9609998418e54396796a4db4ddb3c.tar.xz |
e1000: Properly release SW_FW_SYNC semaphore bits
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>
Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
Diffstat (limited to 'drivers/net')
-rw-r--r-- | drivers/net/e1000/e1000.h | 1 | ||||
-rw-r--r-- | drivers/net/e1000/main.c | 30 |
2 files changed, 31 insertions, 0 deletions
diff --git a/drivers/net/e1000/e1000.h b/drivers/net/e1000/e1000.h index 3859f8c840..c6d26d5787 100644 --- a/drivers/net/e1000/e1000.h +++ b/drivers/net/e1000/e1000.h @@ -2142,6 +2142,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); #endif /* _E1000_HW_H_ */ diff --git a/drivers/net/e1000/main.c b/drivers/net/e1000/main.c index 7ee78c3538..df9ae739ec 100644 --- a/drivers/net/e1000/main.c +++ b/drivers/net/e1000/main.c @@ -273,6 +273,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, E1000_SW_FW_SYNC); + swfw_sync &= ~mask; + e1000_write_reg(hw, E1000_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) { @@ -1347,6 +1362,11 @@ static int32_t e1000_write_kmrn_reg(struct e1000_hw *hw, uint32_t reg_addr, uint e1000_write_reg(hw, E1000_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; } @@ -1374,6 +1394,11 @@ static int32_t e1000_read_kmrn_reg(struct e1000_hw *hw, uint32_t reg_addr, uint1 reg_val = e1000_read_reg(hw, E1000_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; } @@ -2803,6 +2828,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. |