* [PATCH v2 net-next 4/4] net: phy: marvell: Uniform page names
From: Andrew Lunn @ 2017-05-25 19:42 UTC (permalink / raw)
To: David Miller; +Cc: Florian Fainelli, netdev, Andrew Lunn
In-Reply-To: <1495741328-25001-1-git-send-email-andrew@lunn.ch>
Bring all the page names together, remove the repeats, and make them
uniform.
Signed-off-by: Andrew Lunn <andrew@lunn.ch>
---
drivers/net/phy/marvell.c | 94 +++++++++++++++++++++++------------------------
1 file changed, 46 insertions(+), 48 deletions(-)
diff --git a/drivers/net/phy/marvell.c b/drivers/net/phy/marvell.c
index ed338af61cdd..2bd83920f565 100644
--- a/drivers/net/phy/marvell.c
+++ b/drivers/net/phy/marvell.c
@@ -41,6 +41,12 @@
#include <linux/uaccess.h>
#define MII_MARVELL_PHY_PAGE 22
+#define MII_MARVELL_COPPER_PAGE 0x00
+#define MII_MARVELL_FIBER_PAGE 0x01
+#define MII_MARVELL_MSCR_PAGE 0x02
+#define MII_MARVELL_LED_PAGE 0x03
+#define MII_MARVELL_MISC_TEST_PAGE 0x06
+#define MII_MARVELL_WOL_PAGE 0x11
#define MII_M1011_IEVENT 0x13
#define MII_M1011_IEVENT_CLEAR 0x0000
@@ -82,16 +88,11 @@
#define MII_M1111_HWCFG_FIBER_COPPER_AUTO 0x8000
#define MII_M1111_HWCFG_FIBER_COPPER_RES 0x2000
-#define MII_M1111_COPPER 0
-#define MII_M1111_FIBER 1
-
-#define MII_88E1121_PHY_MSCR_PAGE 2
#define MII_88E1121_PHY_MSCR_REG 21
#define MII_88E1121_PHY_MSCR_RX_DELAY BIT(5)
#define MII_88E1121_PHY_MSCR_TX_DELAY BIT(4)
#define MII_88E1121_PHY_MSCR_DELAY_MASK (~(0x3 << 4))
-#define MII_88E1121_MISC_TEST_PAGE 6
#define MII_88E1121_MISC_TEST 0x1a
#define MII_88E1510_MISC_TEST_TEMP_THRESHOLD_MASK 0x1f00
#define MII_88E1510_MISC_TEST_TEMP_THRESHOLD_SHIFT 8
@@ -112,7 +113,6 @@
#define MII_88E1318S_PHY_CSIER_WOL_EIE BIT(7)
/* LED Timer Control Register */
-#define MII_88E1318S_PHY_LED_PAGE 0x03
#define MII_88E1318S_PHY_LED_TCR 0x12
#define MII_88E1318S_PHY_LED_TCR_FORCE_INT BIT(15)
#define MII_88E1318S_PHY_LED_TCR_INTn_ENABLE BIT(7)
@@ -123,13 +123,11 @@
#define MII_88E1318S_PHY_MAGIC_PACKET_WORD1 0x18
#define MII_88E1318S_PHY_MAGIC_PACKET_WORD0 0x19
-#define MII_88E1318S_PHY_WOL_PAGE 0x11
#define MII_88E1318S_PHY_WOL_CTRL 0x10
#define MII_88E1318S_PHY_WOL_CTRL_CLEAR_WOL_STATUS BIT(12)
#define MII_88E1318S_PHY_WOL_CTRL_MAGIC_PACKET_MATCH_ENABLE BIT(14)
#define MII_88E1121_PHY_LED_CTRL 16
-#define MII_88E1121_PHY_LED_PAGE 3
#define MII_88E1121_PHY_LED_DEF 0x0030
#define MII_M1011_PHY_STATUS 0x11
@@ -465,7 +463,7 @@ static int m88e1121_config_aneg(struct phy_device *phydev)
{
int err, oldpage, mscr;
- oldpage = marvell_get_set_page(phydev, MII_88E1121_PHY_MSCR_PAGE);
+ oldpage = marvell_get_set_page(phydev, MII_MARVELL_MSCR_PAGE);
if (oldpage < 0)
return oldpage;
@@ -504,7 +502,7 @@ static int m88e1318_config_aneg(struct phy_device *phydev)
{
int err, oldpage, mscr;
- oldpage = marvell_get_set_page(phydev, MII_88E1121_PHY_MSCR_PAGE);
+ oldpage = marvell_get_set_page(phydev, MII_MARVELL_MSCR_PAGE);
if (oldpage < 0)
return oldpage;
@@ -615,7 +613,7 @@ static int m88e1510_config_aneg(struct phy_device *phydev)
{
int err;
- err = marvell_set_page(phydev, MII_M1111_COPPER);
+ err = marvell_set_page(phydev, MII_MARVELL_COPPER_PAGE);
if (err < 0)
goto error;
@@ -625,7 +623,7 @@ static int m88e1510_config_aneg(struct phy_device *phydev)
goto error;
/* Then the fiber link */
- err = marvell_set_page(phydev, MII_M1111_FIBER);
+ err = marvell_set_page(phydev, MII_MARVELL_FIBER_PAGE);
if (err < 0)
goto error;
@@ -633,10 +631,10 @@ static int m88e1510_config_aneg(struct phy_device *phydev)
if (err < 0)
goto error;
- return marvell_set_page(phydev, MII_M1111_COPPER);
+ return marvell_set_page(phydev, MII_MARVELL_COPPER_PAGE);
error:
- marvell_set_page(phydev, MII_M1111_COPPER);
+ marvell_set_page(phydev, MII_MARVELL_COPPER_PAGE);
return err;
}
@@ -659,7 +657,7 @@ static int m88e1116r_config_init(struct phy_device *phydev)
mdelay(500);
- err = marvell_set_page(phydev, MII_M1111_COPPER);
+ err = marvell_set_page(phydev, MII_MARVELL_COPPER_PAGE);
if (err < 0)
return err;
@@ -671,7 +669,7 @@ static int m88e1116r_config_init(struct phy_device *phydev)
if (err < 0)
return err;
- err = marvell_set_page(phydev, MII_88E1121_PHY_MSCR_PAGE);
+ err = marvell_set_page(phydev, MII_MARVELL_MSCR_PAGE);
if (err < 0)
return err;
temp = phy_read(phydev, MII_M1116R_CONTROL_REG_MAC);
@@ -680,7 +678,7 @@ static int m88e1116r_config_init(struct phy_device *phydev)
err = phy_write(phydev, MII_M1116R_CONTROL_REG_MAC, temp);
if (err < 0)
return err;
- err = marvell_set_page(phydev, MII_M1111_COPPER);
+ err = marvell_set_page(phydev, MII_MARVELL_COPPER_PAGE);
if (err < 0)
return err;
@@ -769,7 +767,7 @@ static int m88e1111_config_init_sgmii(struct phy_device *phydev)
return err;
/* make sure copper is selected */
- return marvell_set_page(phydev, MII_M1111_COPPER);
+ return marvell_set_page(phydev, MII_MARVELL_COPPER_PAGE);
}
static int m88e1111_config_init_rtbi(struct phy_device *phydev)
@@ -852,7 +850,7 @@ static int m88e1121_config_init(struct phy_device *phydev)
{
int err, oldpage;
- oldpage = marvell_get_set_page(phydev, MII_88E1121_PHY_LED_PAGE);
+ oldpage = marvell_get_set_page(phydev, MII_MARVELL_LED_PAGE);
if (oldpage < 0)
return oldpage;
@@ -895,7 +893,7 @@ static int m88e1510_config_init(struct phy_device *phydev)
return err;
/* Reset page selection */
- err = marvell_set_page(phydev, MII_M1111_COPPER);
+ err = marvell_set_page(phydev, MII_MARVELL_COPPER_PAGE);
if (err < 0)
return err;
}
@@ -925,7 +923,7 @@ static int m88e1118_config_init(struct phy_device *phydev)
int err;
/* Change address */
- err = marvell_set_page(phydev, MII_88E1121_PHY_MSCR_PAGE);
+ err = marvell_set_page(phydev, MII_MARVELL_MSCR_PAGE);
if (err < 0)
return err;
@@ -935,7 +933,7 @@ static int m88e1118_config_init(struct phy_device *phydev)
return err;
/* Change address */
- err = marvell_set_page(phydev, MII_88E1318S_PHY_LED_PAGE);
+ err = marvell_set_page(phydev, MII_MARVELL_LED_PAGE);
if (err < 0)
return err;
@@ -952,7 +950,7 @@ static int m88e1118_config_init(struct phy_device *phydev)
return err;
/* Reset address */
- err = marvell_set_page(phydev, MII_M1111_COPPER);
+ err = marvell_set_page(phydev, MII_MARVELL_COPPER_PAGE);
if (err < 0)
return err;
@@ -964,7 +962,7 @@ static int m88e1149_config_init(struct phy_device *phydev)
int err;
/* Change address */
- err = marvell_set_page(phydev, MII_88E1121_PHY_MSCR_PAGE);
+ err = marvell_set_page(phydev, MII_MARVELL_MSCR_PAGE);
if (err < 0)
return err;
@@ -978,7 +976,7 @@ static int m88e1149_config_init(struct phy_device *phydev)
return err;
/* Reset address */
- err = marvell_set_page(phydev, MII_M1111_COPPER);
+ err = marvell_set_page(phydev, MII_MARVELL_COPPER_PAGE);
if (err < 0)
return err;
@@ -1248,7 +1246,7 @@ static int marvell_read_status_page(struct phy_device *phydev, int page)
/* Detect and update the link, but return if there
* was an error
*/
- if (page == MII_M1111_FIBER)
+ if (page == MII_MARVELL_FIBER_PAGE)
fiber = 1;
else
fiber = 0;
@@ -1281,11 +1279,11 @@ static int marvell_read_status(struct phy_device *phydev)
/* Check the fiber mode first */
if (phydev->supported & SUPPORTED_FIBRE &&
phydev->interface != PHY_INTERFACE_MODE_SGMII) {
- err = marvell_set_page(phydev, MII_M1111_FIBER);
+ err = marvell_set_page(phydev, MII_MARVELL_FIBER_PAGE);
if (err < 0)
goto error;
- err = marvell_read_status_page(phydev, MII_M1111_FIBER);
+ err = marvell_read_status_page(phydev, MII_MARVELL_FIBER_PAGE);
if (err < 0)
goto error;
@@ -1300,15 +1298,15 @@ static int marvell_read_status(struct phy_device *phydev)
return 0;
/* If fiber link is down, check and save copper mode state */
- err = marvell_set_page(phydev, MII_M1111_COPPER);
+ err = marvell_set_page(phydev, MII_MARVELL_COPPER_PAGE);
if (err < 0)
goto error;
}
- return marvell_read_status_page(phydev, MII_M1111_COPPER);
+ return marvell_read_status_page(phydev, MII_MARVELL_COPPER_PAGE);
error:
- marvell_set_page(phydev, MII_M1111_COPPER);
+ marvell_set_page(phydev, MII_MARVELL_COPPER_PAGE);
return err;
}
@@ -1323,7 +1321,7 @@ static int marvell_suspend(struct phy_device *phydev)
/* Suspend the fiber mode first */
if (!(phydev->supported & SUPPORTED_FIBRE)) {
- err = marvell_set_page(phydev, MII_M1111_FIBER);
+ err = marvell_set_page(phydev, MII_MARVELL_FIBER_PAGE);
if (err < 0)
goto error;
@@ -1333,7 +1331,7 @@ static int marvell_suspend(struct phy_device *phydev)
goto error;
/* Then, the copper link */
- err = marvell_set_page(phydev, MII_M1111_COPPER);
+ err = marvell_set_page(phydev, MII_MARVELL_COPPER_PAGE);
if (err < 0)
goto error;
}
@@ -1342,7 +1340,7 @@ static int marvell_suspend(struct phy_device *phydev)
return genphy_suspend(phydev);
error:
- marvell_set_page(phydev, MII_M1111_COPPER);
+ marvell_set_page(phydev, MII_MARVELL_COPPER_PAGE);
return err;
}
@@ -1357,7 +1355,7 @@ static int marvell_resume(struct phy_device *phydev)
/* Resume the fiber mode first */
if (!(phydev->supported & SUPPORTED_FIBRE)) {
- err = marvell_set_page(phydev, MII_M1111_FIBER);
+ err = marvell_set_page(phydev, MII_MARVELL_FIBER_PAGE);
if (err < 0)
goto error;
@@ -1367,7 +1365,7 @@ static int marvell_resume(struct phy_device *phydev)
goto error;
/* Then, the copper link */
- err = marvell_set_page(phydev, MII_M1111_COPPER);
+ err = marvell_set_page(phydev, MII_MARVELL_COPPER_PAGE);
if (err < 0)
goto error;
}
@@ -1376,7 +1374,7 @@ static int marvell_resume(struct phy_device *phydev)
return genphy_resume(phydev);
error:
- marvell_set_page(phydev, MII_M1111_COPPER);
+ marvell_set_page(phydev, MII_MARVELL_COPPER_PAGE);
return err;
}
@@ -1405,14 +1403,14 @@ static void m88e1318_get_wol(struct phy_device *phydev,
wol->supported = WAKE_MAGIC;
wol->wolopts = 0;
- if (marvell_set_page(phydev, MII_88E1318S_PHY_WOL_PAGE) < 0)
+ if (marvell_set_page(phydev, MII_MARVELL_WOL_PAGE) < 0)
return;
if (phy_read(phydev, MII_88E1318S_PHY_WOL_CTRL) &
MII_88E1318S_PHY_WOL_CTRL_MAGIC_PACKET_MATCH_ENABLE)
wol->wolopts |= WAKE_MAGIC;
- if (marvell_set_page(phydev, MII_M1111_COPPER) < 0)
+ if (marvell_set_page(phydev, MII_MARVELL_COPPER_PAGE) < 0)
return;
}
@@ -1425,7 +1423,7 @@ static int m88e1318_set_wol(struct phy_device *phydev,
if (wol->wolopts & WAKE_MAGIC) {
/* Explicitly switch to page 0x00, just to be sure */
- err = marvell_set_page(phydev, MII_M1111_COPPER);
+ err = marvell_set_page(phydev, MII_MARVELL_COPPER_PAGE);
if (err < 0)
return err;
@@ -1436,7 +1434,7 @@ static int m88e1318_set_wol(struct phy_device *phydev,
if (err < 0)
return err;
- err = marvell_set_page(phydev, MII_88E1318S_PHY_LED_PAGE);
+ err = marvell_set_page(phydev, MII_MARVELL_LED_PAGE);
if (err < 0)
return err;
@@ -1449,7 +1447,7 @@ static int m88e1318_set_wol(struct phy_device *phydev,
if (err < 0)
return err;
- err = marvell_set_page(phydev, MII_88E1318S_PHY_WOL_PAGE);
+ err = marvell_set_page(phydev, MII_MARVELL_WOL_PAGE);
if (err < 0)
return err;
@@ -1478,7 +1476,7 @@ static int m88e1318_set_wol(struct phy_device *phydev,
if (err < 0)
return err;
} else {
- err = marvell_set_page(phydev, MII_88E1318S_PHY_WOL_PAGE);
+ err = marvell_set_page(phydev, MII_MARVELL_WOL_PAGE);
if (err < 0)
return err;
@@ -1564,7 +1562,7 @@ static int m88e1121_get_temp(struct phy_device *phydev, long *temp)
mutex_lock(&phydev->lock);
- oldpage = marvell_get_set_page(phydev, MII_88E1121_MISC_TEST_PAGE);
+ oldpage = marvell_get_set_page(phydev, MII_MARVELL_MISC_TEST_PAGE);
if (oldpage < 0) {
mutex_unlock(&phydev->lock);
return oldpage;
@@ -1682,7 +1680,7 @@ static int m88e1510_get_temp(struct phy_device *phydev, long *temp)
mutex_lock(&phydev->lock);
- oldpage = marvell_get_set_page(phydev, MII_88E1121_MISC_TEST_PAGE);
+ oldpage = marvell_get_set_page(phydev, MII_MARVELL_MISC_TEST_PAGE);
if (oldpage < 0) {
mutex_unlock(&phydev->lock);
return oldpage;
@@ -1710,7 +1708,7 @@ int m88e1510_get_temp_critical(struct phy_device *phydev, long *temp)
mutex_lock(&phydev->lock);
- oldpage = marvell_get_set_page(phydev, MII_88E1121_MISC_TEST_PAGE);
+ oldpage = marvell_get_set_page(phydev, MII_MARVELL_MISC_TEST_PAGE);
if (oldpage < 0) {
mutex_unlock(&phydev->lock);
return oldpage;
@@ -1739,7 +1737,7 @@ int m88e1510_set_temp_critical(struct phy_device *phydev, long temp)
mutex_lock(&phydev->lock);
- oldpage = marvell_get_set_page(phydev, MII_88E1121_MISC_TEST_PAGE);
+ oldpage = marvell_get_set_page(phydev, MII_MARVELL_MISC_TEST_PAGE);
if (oldpage < 0) {
mutex_unlock(&phydev->lock);
return oldpage;
@@ -1771,7 +1769,7 @@ int m88e1510_get_temp_alarm(struct phy_device *phydev, long *alarm)
mutex_lock(&phydev->lock);
- oldpage = marvell_get_set_page(phydev, MII_88E1121_MISC_TEST_PAGE);
+ oldpage = marvell_get_set_page(phydev, MII_MARVELL_MISC_TEST_PAGE);
if (oldpage < 0) {
mutex_unlock(&phydev->lock);
return oldpage;
--
2.11.0
^ permalink raw reply related
* [PATCH v2 net-next 2/4] net: phy: marvell: More hidden page changes refactored
From: Andrew Lunn @ 2017-05-25 19:42 UTC (permalink / raw)
To: David Miller; +Cc: Florian Fainelli, netdev, Andrew Lunn
In-Reply-To: <1495741328-25001-1-git-send-email-andrew@lunn.ch>
EXT_ADDR_PAGE is the same meaning as MII_MARVELL_PHY_PAGE, i.e. change
page. Replace it will calls to the helpers.
Signed-off-by: Andrew Lunn <andrew@lunn.ch>
---
drivers/net/phy/marvell.c | 62 +++++++++++++++++++++++++++++++++++------------
1 file changed, 46 insertions(+), 16 deletions(-)
diff --git a/drivers/net/phy/marvell.c b/drivers/net/phy/marvell.c
index bb067026353a..3c577a177b2c 100644
--- a/drivers/net/phy/marvell.c
+++ b/drivers/net/phy/marvell.c
@@ -54,7 +54,6 @@
#define MII_M1011_PHY_SCR_MDI_X 0x0020
#define MII_M1011_PHY_SCR_AUTO_CROSS 0x0060
-#define MII_M1145_PHY_EXT_ADDR_PAGE 0x16
#define MII_M1145_PHY_EXT_SR 0x1b
#define MII_M1145_PHY_EXT_CR 0x14
#define MII_M1145_RGMII_RX_DELAY 0x0080
@@ -92,6 +91,7 @@
#define MII_88E1121_PHY_MSCR_TX_DELAY BIT(4)
#define MII_88E1121_PHY_MSCR_DELAY_MASK (~(0x3 << 4))
+#define MII_88E1121_MISC_TEST_PAGE 6
#define MII_88E1121_MISC_TEST 0x1a
#define MII_88E1510_MISC_TEST_TEMP_THRESHOLD_MASK 0x1f00
#define MII_88E1510_MISC_TEST_TEMP_THRESHOLD_SHIFT 8
@@ -760,11 +760,7 @@ static int m88e1111_config_init_sgmii(struct phy_device *phydev)
return err;
/* make sure copper is selected */
- err = phy_read(phydev, MII_M1145_PHY_EXT_ADDR_PAGE);
- if (err < 0)
- return err;
-
- return phy_write(phydev, MII_M1145_PHY_EXT_ADDR_PAGE, err & (~0xff));
+ return marvell_set_page(phydev, MII_M1111_COPPER);
}
static int m88e1111_config_init_rtbi(struct phy_device *phydev)
@@ -1554,6 +1550,7 @@ static void marvell_get_stats(struct phy_device *phydev,
#ifdef CONFIG_HWMON
static int m88e1121_get_temp(struct phy_device *phydev, long *temp)
{
+ int oldpage;
int ret;
int val;
@@ -1561,7 +1558,13 @@ static int m88e1121_get_temp(struct phy_device *phydev, long *temp)
mutex_lock(&phydev->lock);
- ret = phy_write(phydev, MII_M1145_PHY_EXT_ADDR_PAGE, 0x6);
+ oldpage = marvell_get_page(phydev);
+ if (oldpage < 0) {
+ mutex_unlock(&phydev->lock);
+ return oldpage;
+ }
+
+ ret = marvell_set_page(phydev, MII_88E1121_MISC_TEST_PAGE);
if (ret < 0)
goto error;
@@ -1593,7 +1596,7 @@ static int m88e1121_get_temp(struct phy_device *phydev, long *temp)
*temp = ((val & MII_88E1121_MISC_TEST_TEMP_MASK) - 5) * 5000;
error:
- phy_write(phydev, MII_M1145_PHY_EXT_ADDR_PAGE, 0x0);
+ marvell_set_page(phydev, oldpage);
mutex_unlock(&phydev->lock);
return ret;
@@ -1670,13 +1673,20 @@ static const struct hwmon_chip_info m88e1121_hwmon_chip_info = {
static int m88e1510_get_temp(struct phy_device *phydev, long *temp)
{
+ int oldpage;
int ret;
*temp = 0;
mutex_lock(&phydev->lock);
- ret = phy_write(phydev, MII_M1145_PHY_EXT_ADDR_PAGE, 0x6);
+ oldpage = marvell_get_page(phydev);
+ if (oldpage < 0) {
+ mutex_unlock(&phydev->lock);
+ return oldpage;
+ }
+
+ ret = marvell_set_page(phydev, MII_88E1121_MISC_TEST_PAGE);
if (ret < 0)
goto error;
@@ -1687,7 +1697,7 @@ static int m88e1510_get_temp(struct phy_device *phydev, long *temp)
*temp = ((ret & MII_88E1510_TEMP_SENSOR_MASK) - 25) * 1000;
error:
- phy_write(phydev, MII_M1145_PHY_EXT_ADDR_PAGE, 0x0);
+ marvell_set_page(phydev, oldpage);
mutex_unlock(&phydev->lock);
return ret;
@@ -1695,13 +1705,19 @@ static int m88e1510_get_temp(struct phy_device *phydev, long *temp)
int m88e1510_get_temp_critical(struct phy_device *phydev, long *temp)
{
+ int oldpage;
int ret;
*temp = 0;
mutex_lock(&phydev->lock);
+ oldpage = marvell_get_page(phydev);
+ if (oldpage < 0) {
+ mutex_unlock(&phydev->lock);
+ return oldpage;
+ }
- ret = phy_write(phydev, MII_M1145_PHY_EXT_ADDR_PAGE, 0x6);
+ ret = marvell_set_page(phydev, MII_88E1121_MISC_TEST_PAGE);
if (ret < 0)
goto error;
@@ -1715,7 +1731,7 @@ int m88e1510_get_temp_critical(struct phy_device *phydev, long *temp)
*temp *= 1000;
error:
- phy_write(phydev, MII_M1145_PHY_EXT_ADDR_PAGE, 0x0);
+ marvell_set_page(phydev, oldpage);
mutex_unlock(&phydev->lock);
return ret;
@@ -1723,11 +1739,18 @@ int m88e1510_get_temp_critical(struct phy_device *phydev, long *temp)
int m88e1510_set_temp_critical(struct phy_device *phydev, long temp)
{
+ int oldpage;
int ret;
mutex_lock(&phydev->lock);
- ret = phy_write(phydev, MII_M1145_PHY_EXT_ADDR_PAGE, 0x6);
+ oldpage = marvell_get_page(phydev);
+ if (oldpage < 0) {
+ mutex_unlock(&phydev->lock);
+ return oldpage;
+ }
+
+ ret = marvell_set_page(phydev, MII_88E1121_MISC_TEST_PAGE);
if (ret < 0)
goto error;
@@ -1742,7 +1765,7 @@ int m88e1510_set_temp_critical(struct phy_device *phydev, long temp)
(temp << MII_88E1510_MISC_TEST_TEMP_THRESHOLD_SHIFT));
error:
- phy_write(phydev, MII_M1145_PHY_EXT_ADDR_PAGE, 0x0);
+ marvell_set_page(phydev, oldpage);
mutex_unlock(&phydev->lock);
return ret;
@@ -1750,13 +1773,20 @@ int m88e1510_set_temp_critical(struct phy_device *phydev, long temp)
int m88e1510_get_temp_alarm(struct phy_device *phydev, long *alarm)
{
+ int oldpage;
int ret;
*alarm = false;
mutex_lock(&phydev->lock);
- ret = phy_write(phydev, MII_M1145_PHY_EXT_ADDR_PAGE, 0x6);
+ oldpage = marvell_get_page(phydev);
+ if (oldpage < 0) {
+ mutex_unlock(&phydev->lock);
+ return oldpage;
+ }
+
+ ret = marvell_set_page(phydev, MII_88E1121_MISC_TEST_PAGE);
if (ret < 0)
goto error;
@@ -1766,7 +1796,7 @@ int m88e1510_get_temp_alarm(struct phy_device *phydev, long *alarm)
*alarm = !!(ret & MII_88E1510_MISC_TEST_TEMP_IRQ);
error:
- phy_write(phydev, MII_M1145_PHY_EXT_ADDR_PAGE, 0x0);
+ marvell_set_page(phydev, oldpage);
mutex_unlock(&phydev->lock);
return ret;
--
2.11.0
^ permalink raw reply related
* [PATCH v2 net-next 0/4] More marvell phy cleanups
From: Andrew Lunn @ 2017-05-25 19:42 UTC (permalink / raw)
To: David Miller; +Cc: Florian Fainelli, netdev, Andrew Lunn
This patchset continues the cleanup of the Marvell PHY driver. These
phys use pages to allow more than the 32 registers that fit into the
MDIO address space. Cleanup the code used for changing pages.
v2
Reverse christmas tree
Andrew Lunn (4):
net: phy: marvell: #defines for copper and fibre pages
net: phy: marvell: More hidden page changes refactored
net: phy: marvell: helper to get and set page
net: phy: marvell: Uniform page names
drivers/net/phy/marvell.c | 181 +++++++++++++++++++++++++---------------------
1 file changed, 98 insertions(+), 83 deletions(-)
--
2.11.0
^ permalink raw reply
* [PATCH v2 net-next 1/4] net: phy: marvell: #defines for copper and fibre pages
From: Andrew Lunn @ 2017-05-25 19:42 UTC (permalink / raw)
To: David Miller; +Cc: Florian Fainelli, netdev, Andrew Lunn
In-Reply-To: <1495741328-25001-1-git-send-email-andrew@lunn.ch>
Replace magic numbers for PHY pages with symbolic names.
Signed-off-by: Andrew Lunn <andrew@lunn.ch>
---
drivers/net/phy/marvell.c | 22 +++++++++++-----------
1 file changed, 11 insertions(+), 11 deletions(-)
diff --git a/drivers/net/phy/marvell.c b/drivers/net/phy/marvell.c
index 88cd97b44ba6..bb067026353a 100644
--- a/drivers/net/phy/marvell.c
+++ b/drivers/net/phy/marvell.c
@@ -650,7 +650,7 @@ static int m88e1116r_config_init(struct phy_device *phydev)
mdelay(500);
- err = marvell_set_page(phydev, 0);
+ err = marvell_set_page(phydev, MII_M1111_COPPER);
if (err < 0)
return err;
@@ -662,7 +662,7 @@ static int m88e1116r_config_init(struct phy_device *phydev)
if (err < 0)
return err;
- err = marvell_set_page(phydev, 2);
+ err = marvell_set_page(phydev, MII_88E1121_PHY_MSCR_PAGE);
if (err < 0)
return err;
temp = phy_read(phydev, MII_M1116R_CONTROL_REG_MAC);
@@ -671,7 +671,7 @@ static int m88e1116r_config_init(struct phy_device *phydev)
err = phy_write(phydev, MII_M1116R_CONTROL_REG_MAC, temp);
if (err < 0)
return err;
- err = marvell_set_page(phydev, 0);
+ err = marvell_set_page(phydev, MII_M1111_COPPER);
if (err < 0)
return err;
@@ -892,7 +892,7 @@ static int m88e1510_config_init(struct phy_device *phydev)
return err;
/* Reset page selection */
- err = marvell_set_page(phydev, 0);
+ err = marvell_set_page(phydev, MII_M1111_COPPER);
if (err < 0)
return err;
}
@@ -922,7 +922,7 @@ static int m88e1118_config_init(struct phy_device *phydev)
int err;
/* Change address */
- err = marvell_set_page(phydev, 2);
+ err = marvell_set_page(phydev, MII_88E1121_PHY_MSCR_PAGE);
if (err < 0)
return err;
@@ -932,7 +932,7 @@ static int m88e1118_config_init(struct phy_device *phydev)
return err;
/* Change address */
- err = marvell_set_page(phydev, 3);
+ err = marvell_set_page(phydev, MII_88E1318S_PHY_LED_PAGE);
if (err < 0)
return err;
@@ -949,7 +949,7 @@ static int m88e1118_config_init(struct phy_device *phydev)
return err;
/* Reset address */
- err = marvell_set_page(phydev, 0);
+ err = marvell_set_page(phydev, MII_M1111_COPPER);
if (err < 0)
return err;
@@ -961,7 +961,7 @@ static int m88e1149_config_init(struct phy_device *phydev)
int err;
/* Change address */
- err = marvell_set_page(phydev, 2);
+ err = marvell_set_page(phydev, MII_88E1121_PHY_MSCR_PAGE);
if (err < 0)
return err;
@@ -975,7 +975,7 @@ static int m88e1149_config_init(struct phy_device *phydev)
return err;
/* Reset address */
- err = marvell_set_page(phydev, 0);
+ err = marvell_set_page(phydev, MII_M1111_COPPER);
if (err < 0)
return err;
@@ -1409,7 +1409,7 @@ static void m88e1318_get_wol(struct phy_device *phydev,
MII_88E1318S_PHY_WOL_CTRL_MAGIC_PACKET_MATCH_ENABLE)
wol->wolopts |= WAKE_MAGIC;
- if (marvell_set_page(phydev, 0x00) < 0)
+ if (marvell_set_page(phydev, MII_M1111_COPPER) < 0)
return;
}
@@ -1422,7 +1422,7 @@ static int m88e1318_set_wol(struct phy_device *phydev,
if (wol->wolopts & WAKE_MAGIC) {
/* Explicitly switch to page 0x00, just to be sure */
- err = marvell_set_page(phydev, 0x00);
+ err = marvell_set_page(phydev, MII_M1111_COPPER);
if (err < 0)
return err;
--
2.11.0
^ permalink raw reply related
* Re: [PATCH net-next 6/6] net: mpls: minor cleanups
From: Joe Perches @ 2017-05-25 19:46 UTC (permalink / raw)
To: David Miller, dsahern; +Cc: netdev, roopa
In-Reply-To: <20170525.145631.1427287907712541949.davem@davemloft.net>
On Thu, 2017-05-25 at 14:56 -0400, David Miller wrote:
> From: David Ahern <dsahern@gmail.com>
> Date: Wed, 24 May 2017 21:54:42 -0600
>
> > Noticed these doing the extack support:
> > - nla_get_via is only used in af_mpls.c so remove from internal.h
> ...
> > @@ -43,6 +43,9 @@ static void rtmsg_lfib(int event, u32 label, struct mpls_route *rt,
> > struct nlmsghdr *nlh, struct net *net, u32 portid,
> > unsigned int nlm_flags);
> >
> > +static int nla_get_via(const struct nlattr *nla, u8 *via_alen, u8 *via_table,
> > + u8 via[], struct netlink_ext_ack *extack);
> > +
> > static struct mpls_route *mpls_route_input_rcu(struct net *net, unsigned index)
> > {
> > struct mpls_route *rt = NULL;
>
> David, please mark the actual defintion static as well.
>
> I'm surprised the compiler accepts this, but it does :-)
As well, the function should be reordered
in the file to avoid the prototype.
Something like:
---
net/mpls/af_mpls.c | 84 ++++++++++++++++++++++++++---------------------------
net/mpls/internal.h | 2 --
2 files changed, 42 insertions(+), 44 deletions(-)
diff --git a/net/mpls/af_mpls.c b/net/mpls/af_mpls.c
index 257ec66009da..9b534dc25b9b 100644
--- a/net/mpls/af_mpls.c
+++ b/net/mpls/af_mpls.c
@@ -718,6 +718,48 @@ static int mpls_nh_build_from_cfg(struct mpls_route_config *cfg,
return err;
}
+static int nla_get_via(const struct nlattr *nla, u8 *via_alen,
+ u8 *via_table, u8 via_addr[])
+{
+ struct rtvia *via = nla_data(nla);
+ int err = -EINVAL;
+ int alen;
+
+ if (nla_len(nla) < offsetof(struct rtvia, rtvia_addr))
+ goto errout;
+ alen = nla_len(nla) -
+ offsetof(struct rtvia, rtvia_addr);
+ if (alen > MAX_VIA_ALEN)
+ goto errout;
+
+ /* Validate the address family */
+ switch (via->rtvia_family) {
+ case AF_PACKET:
+ *via_table = NEIGH_LINK_TABLE;
+ break;
+ case AF_INET:
+ *via_table = NEIGH_ARP_TABLE;
+ if (alen != 4)
+ goto errout;
+ break;
+ case AF_INET6:
+ *via_table = NEIGH_ND_TABLE;
+ if (alen != 16)
+ goto errout;
+ break;
+ default:
+ /* Unsupported address family */
+ goto errout;
+ }
+
+ memcpy(via_addr, via->rtvia_addr, alen);
+ *via_alen = alen;
+ err = 0;
+
+errout:
+ return err;
+}
+
static int mpls_nh_build(struct net *net, struct mpls_route *rt,
struct mpls_nh *nh, int oif, struct nlattr *via,
struct nlattr *newdst, u8 max_labels)
@@ -1594,48 +1636,6 @@ int nla_get_labels(const struct nlattr *nla,
}
EXPORT_SYMBOL_GPL(nla_get_labels);
-int nla_get_via(const struct nlattr *nla, u8 *via_alen,
- u8 *via_table, u8 via_addr[])
-{
- struct rtvia *via = nla_data(nla);
- int err = -EINVAL;
- int alen;
-
- if (nla_len(nla) < offsetof(struct rtvia, rtvia_addr))
- goto errout;
- alen = nla_len(nla) -
- offsetof(struct rtvia, rtvia_addr);
- if (alen > MAX_VIA_ALEN)
- goto errout;
-
- /* Validate the address family */
- switch (via->rtvia_family) {
- case AF_PACKET:
- *via_table = NEIGH_LINK_TABLE;
- break;
- case AF_INET:
- *via_table = NEIGH_ARP_TABLE;
- if (alen != 4)
- goto errout;
- break;
- case AF_INET6:
- *via_table = NEIGH_ND_TABLE;
- if (alen != 16)
- goto errout;
- break;
- default:
- /* Unsupported address family */
- goto errout;
- }
-
- memcpy(via_addr, via->rtvia_addr, alen);
- *via_alen = alen;
- err = 0;
-
-errout:
- return err;
-}
-
static int rtm_to_route_config(struct sk_buff *skb, struct nlmsghdr *nlh,
struct mpls_route_config *cfg)
{
diff --git a/net/mpls/internal.h b/net/mpls/internal.h
index 4db6a5971322..b431c6d3893f 100644
--- a/net/mpls/internal.h
+++ b/net/mpls/internal.h
@@ -204,8 +204,6 @@ int nla_put_labels(struct sk_buff *skb, int attrtype, u8 labels,
const u32 label[]);
int nla_get_labels(const struct nlattr *nla, u8 max_labels, u8 *labels,
u32 label[]);
-int nla_get_via(const struct nlattr *nla, u8 *via_alen, u8 *via_table,
- u8 via[]);
bool mpls_output_possible(const struct net_device *dev);
unsigned int mpls_dev_mtu(const struct net_device *dev);
bool mpls_pkt_too_big(const struct sk_buff *skb, unsigned int mtu);
^ permalink raw reply related
* Re: [PATCH net] ip6_tunnel, ip6_gre: fix setting of DSCP on encapsulated packets
From: Peter Dawson @ 2017-05-25 19:46 UTC (permalink / raw)
To: David Miller
Cc: kuznet, jmorris, yoshfuji, kaber, stephen, netdev, linux-kernel
In-Reply-To: <20170525.121117.810915705354733044.davem@davemloft.net>
On Thu, 25 May 2017 12:11:17 -0400 (EDT)
David Miller <davem@davemloft.net> wrote:
> > Fixes: https://bugzilla.kernel.org/show_bug.cgi?id=195661
>
> This is not the correct way to use the Fixes: tag.
>
> You should specify the commit that introduced the regression
> between 4.9.x and 4.10.x, and that you are fixing here.
Thanks for your review Dave. I'll resubmit the patch with the following detail and just reference the bugzilla in the main body of the commit comment.
Commit 90427ef5d2a4 ("ipv6: fix flow labels when the traffic class is non-0") caused the regression by masking out the flowlabel which exposed the incorrect the handling of the DSCP portion of the flowlabel in ip6_tunnel and ip6_gre.
^ permalink raw reply
* Re: [PATCH net] ip6_tunnel, ip6_gre: fix setting of DSCP on encapsulated packets
From: David Miller @ 2017-05-25 19:49 UTC (permalink / raw)
To: petedaws; +Cc: kuznet, jmorris, yoshfuji, kaber, stephen, netdev, linux-kernel
In-Reply-To: <20170526054627.00dcdeeb@udesktop>
From: Peter Dawson <petedaws@gmail.com>
Date: Fri, 26 May 2017 05:46:27 +1000
> On Thu, 25 May 2017 12:11:17 -0400 (EDT)
> David Miller <davem@davemloft.net> wrote:
>
>> > Fixes: https://bugzilla.kernel.org/show_bug.cgi?id=195661
>>
>> This is not the correct way to use the Fixes: tag.
>>
>> You should specify the commit that introduced the regression
>> between 4.9.x and 4.10.x, and that you are fixing here.
>
> Thanks for your review Dave. I'll resubmit the patch with the following detail and just reference the bugzilla in the main body of the commit comment.
>
> Commit 90427ef5d2a4 ("ipv6: fix flow labels when the traffic class is non-0") caused the regression by masking out the flowlabel which exposed the incorrect the handling of the DSCP portion of the flowlabel in ip6_tunnel and ip6_gre.
Still not correct, you need to use a "Fixes: " tag of the form:
Fixes: 90427ef5d2a4 ("ipv6: fix flow labels when the traffic class is non-0")
And it must appear of the first line of tags, before signoffs and acks,
with no empty lines in between.
Thank you.
^ permalink raw reply
* Re: [PATCH 1/2] PCI: Add new PCIe Fabric End Node flag, PCI_DEV_FLAGS_NO_RELAXED_ORDERING
From: Alexander Duyck @ 2017-05-25 19:49 UTC (permalink / raw)
To: Ding Tianhong
Cc: Casey Leedom, Raj, Ashok, Bjorn Helgaas, Michael Werner,
Ganesh GR, Arjun V., Asit K Mallick, Patrick J Cramer,
Suravee Suthikulpanit, Bob Shaw, h, Mark Rutland, Amir Ancel,
Gabriele Paoloni, Catalin Marinas, Will Deacon, LinuxArm,
David Laight, Jeff Kirsher, Netdev
In-Reply-To: <2eab1a1d-3444-fe11-7626-5b6459e954f8@huawei.com>
On Thu, May 25, 2017 at 6:35 AM, Ding Tianhong <dingtianhong@huawei.com> wrote:
>
> On 2017/5/9 8:48, Casey Leedom wrote:
>>
>> | From: Alexander Duyck <alexander.duyck@gmail.com>
>> | Date: Saturday, May 6, 2017 11:07 AM
>> |
>> | | From: Ding Tianhong <dingtianhong@huawei.com>
>> | | Date: Fri, May 5, 2017 at 8:08 PM
>> | |
>> | | According the suggestion, I could only think of this code:
>> | | ..
>> |
>> | This is a bit simplistic but it is a start.
>>
>> Yes, something tells me that this is going to be more complicated than any
>> of us like ...
>>
>> | The other bit I was getting at is that we need to update the core PCIe
>> | code so that when we configure devices and the root complex reports no
>> | support for relaxed ordering it should be clearing the relaxed
>> | ordering bits in the PCIe configuration registers on the upstream
>> | facing devices.
>>
>> Of course, this can be written to by the Driver at any time ... and is in
>> the case of the cxgb4 Driver ...
>>
>> After a lot of rummaging around, it does look like KVM prohibits writes to
>> the PCIe Capability Device Control register in drivers/xen/xen-pciback/
>> conf_space_capability.c and conf_space.c simply because writes aren't
>> allowed unless "permissive" is set. So it ~looks~ like a driver running in
>> a Virtual Machine can't turn Enable Relaxed Ordering back on ...
>>
>> | The last bit we need in all this is a way to allow for setups where
>> | peer-to-peer wants to perform relaxed ordering but for writes to the
>> | host we have to not use relaxed ordering. For that we need to enable a
>> | special case and that isn't handled right now in any of the solutions
>> | we have coded up so far.
>>
>> Yes, we do need this.
>>
>>
>> | From: Alexander Duyck <alexander.duyck@gmail.com>
>> | Date: Saturday, May 8, 2017 08:22 AM
>> |
>> | The problem is we need to have something that can be communicated
>> | through a VM. Your change doesn't work in that regard. That was why I
>> | suggested just updating the code so that we when we initialized PCIe
>> | devices what we do is either set or clear the relaxed ordering bit in
>> | the PCIe device control register. That way when we direct assign an
>> | interface it could know just based on the bits int the PCIe
>> | configuration if it could use relaxed ordering or not.
>> |
>> | At that point the driver code itself becomes very simple since you
>> | could just enable the relaxed ordering by default in the igb/ixgbe
>> | driver and if the bit is set or cleared in the PCIe configuration then
>> | we are either sending with relaxed ordering requests or not and don't
>> | have to try and locate the root complex.
>> |
>> | So from the sound of it Casey has a special use case where he doesn't
>> | want to send relaxed ordering frames to the root complex, but instead
>> | would like to send them to another PCIe device. To do that he needs to
>> | have a way to enable the relaxed ordering bit in the PCIe
>> | configuration but then not send any to the root complex. Odds are that
>> | is something he might be able to just implement in the driver, but is
>> | something that may become a more general case in the future. I don't
>> | see our change here impacting it as long as we keep the solution
>> | generic and mostly confined to when we instantiate the devices as the
>> | driver could likely make the decision to change the behavior later.
>>
>> It's not just me. Intel has said that while RO directed at the Root
>> Complex Host Coherent Memory has a performance bug (not Data Corruption),
>> it's a performance win for Peer-to-Peer writes to MMIO Space. (I'll be very
>> interested in hearing what the bug is if we get that much detail. The very
>> same TLPs directed to the Root Complex Port without Relaxed Ordering set get
>> good performance. So this is essentially a bug in the hardware that was
>> ~trying~ to implement a performance win.)
>>
>> Meanwhile, I currently only know of a single PCIe End Point which causes
>> catastrophic results: the AMD A1100 ARM SoC ("SEATTLE"). And it's not even
>> clear that product is even alive anymore since I haven't been able to get
>> any responses from them for several months.
>>
>> What I'm saying is: let's try to architect a solution which doesn't throw
>> the baby out with the bath water ...
>>
>> I think that if a Device's Root Complex Port has problems with Relaxed
>> Ordering, it ~probably~ makes sense to turn off the PCIe Capability Device
>> Control[Enable Relaxed Ordering] when we assign a device to a Virtual
>> Machine since the Device Driver can no longer query the Relaxed Ordering
>> Support of the Root Complex Port. The only down side of this would be if we
>> assigned two Peers to a VM in an application which wanted to do Peer-to-Peer
>> transfers. But that seems like a hard application to support in any case
>> since the PCI Bus:Slot.Function IDs for assigned Devices within a VM don't
>> match the actual values.
>>
>> For Devices running in the base OS/Hypervisor, their Drivers can query the
>> Relaxed Ordering Support for the Root Complex Port or a Peer Device. So a
>> simple flag within the (struct pci_dev *)->dev_flags would serve for that
>> along with a per-Architecture/Platform mechanism for setting it ...
>>
>> Casey
>>
>
> I have take a time to talk to our kvm team about how to distinguish the relaxed
> ordering in the VM for some vf just like 82599-vf, the probe routine looks like
> could work like this:
> 1) QEMU could emulate the platform by the Vender ID and device ID which could be
> read from the host.
> 2) The QEMU could create a virtual PCIe dev complex and recognize the PCIe bus address which
> come and detach from the host to the guest.
> 3) the PCI quirk could enable the Relaxed Ordering by the Vendor ID and Device ID.
> 4) The VF drivers could read the flag and set to the hw.
>
> So I think we could set the PCI_DEV_FLAGS_RELAXED_ORDERING_ENABLED for some special platform
> and don't enable by default, if I miss something, please not hesitate to enlighten me :)
This isn't what I had in mind at all.
So what Casey had originally submitted was a step in the direction of
what I was thinking. Basically on platforms where it is not advisable
to enable relaxed ordering we need to advertise that relaxed ordering
is not safe. Then when we are initializing the devices underneath
those we need to be clearing the relaxed ordering enable bits in the
PCI configuration, that is the piece that was missing from Casey's
original patch. In addition we then need to have a way for devices to
optionally enable relaxed ordering for cases like Casey pointed out
where they might want to use relaxed ordering for peer-to-peer
transactions, but not for transactions to the root complex. Finally in
the case of the Intel drivers we could then just drop the compile time
checks entirely and just enable the device to configure the internal
registers for relaxed ordering because the configuration space becomes
the spot that controls if this gets enabled or not.
So the initial set of patches Casey submitted only really consisted of
2 patches. What I am proposing is that we would be looking at
expanding this out to about 4 patches. The first patch is the original
1 of 2, the second patch would be to modify the PCI initialization
code to clear the relaxed ordering enable bit in the event that the
root complex doesn't want relaxed ordering enabled, the third would be
to make changes to the Chelsio driver as needed to allow for the
peer-to-peer case to be enabled when the relaxed ordering bit in the
configuration space is not enabled without triggering any relaxed
ordering requests to the root complex, and the last one would be to
drop the defines in ixgbe and whatever other Intel drivers are
currently checking for either SPARC or the define that was added to
support relaxed ordering and just act like we are going to do it
always with the PCI configuration space controlling if we do or not.
Ideally as a part of the second patch we should have a way of testing
if a given path can support relaxed ordering. That way when we go to
try to enable a peer-to-peer setup we can be certain that a given path
will work and don't try enabling it in paths that would be unsupported
for peer-to-peer.
This ends up being somewhat of a risk for the Intel NICs, but if the
Chelsio devices have been running with relaxed ordering enabled for
some time and have identified the chipsets that should be issues, then
odds are we should be fine as well.
> --------------------------------------------------------------
> diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c
> index 085fb78..74bcc25 100644
> --- a/drivers/pci/quirks.c
> +++ b/drivers/pci/quirks.c
> @@ -4664,3 +4664,22 @@ static void quirk_intel_no_flr(struct pci_dev *dev)
> }
> DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, 0x1502, quirk_intel_no_flr);
> DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, 0x1503, quirk_intel_no_flr);
> +
> +/*
> + * Some devices have problems with Transaction Layer Packets with the Relaxed
> + * Ordering Attribute set, so we should disable Relaxed Ordering by default
> + * and only enable it when some devices has mark themselves and other
> + * Device Drivers should check before sending TLPs with RO set.
> + */
> +static void quirk_relaxedordering_enable(struct pci_dev *dev)
> +{
> + dev->dev_flags &= ~PCI_DEV_FLAGS_RELAXED_ORDERING_ENABLED;
> +}
> +
> +/*
> + * Hisilicon Root Complex could support relaxed ordering which can
> + * improve performance with Upstream Transaction Layer Packets with
> + * Relaxed Ordering set.
> + */
> +DECLARE_PCI_FIXUP_CLASS_EARLY(PCI_VENDOR_ID_HUAWEI, 0x1610, PCI_CLASS_NOT_DEFINED, 8,
> + quirk_relaxedordering_enable);
> diff --git a/include/linux/pci.h b/include/linux/pci.h
> index 33c2b0b..f7d8d6f 100644
> --- a/include/linux/pci.h
> +++ b/include/linux/pci.h
> @@ -183,6 +183,8 @@ enum pci_dev_flags {
> PCI_DEV_FLAGS_BRIDGE_XLATE_ROOT = (__force pci_dev_flags_t) (1 << 9),
> /* Do not use FLR even if device advertises PCI_AF_CAP */
> PCI_DEV_FLAGS_NO_FLR_RESET = (__force pci_dev_flags_t) (1 << 10),
> + /* Use Relaxed Ordering for TLPs directed at this device */
> + PCI_DEV_FLAGS_RELAXED_ORDERING_ENABLED = (__force pci_dev_flags_t) (1 << 11),
> };
>
> enum pci_irq_reroute_variant {
> @@ -2203,6 +2205,20 @@ static inline bool pci_is_thunderbolt_attached(struct pci_dev *pdev)
> return false;
> }
>
> +/**
> + * pci_is_dev_relaxed_ordering_enabled - whether device could support Relaxed
> + * Ordering for TLPs directed.
> + * @pdev: PCI device to check
> + *
> + * This function could return the value indicates that whether Relaxed Ordering
> + * Attribute could be used on Transaction Layer Packets destined for the PCIe
> + * End Node.
> + */
> +static inline boot pci_is_dev_relaxed_ordering_enabled(struct pci_dev *pdev)
> +{
> + return (pdev->dev_flags & PCI_DEV_FLAGS_RELAXED_ORDERING_ENABLED) ==
> + PCI_DEV_FLAGS_RELAXED_ORDERING_ENABLED;
> /* provide the legacy pci_dma_* API */
> #include <linux/pci-dma-compat.h>
>
> Thanks
> Ding
>
>> .
>>
>
^ permalink raw reply
* Re: [PATCH net] ip6_tunnel, ip6_gre: fix setting of DSCP on encapsulated packets
From: Peter Dawson @ 2017-05-25 20:08 UTC (permalink / raw)
To: David Miller
Cc: kuznet, jmorris, yoshfuji, kaber, stephen, netdev, linux-kernel
In-Reply-To: <20170525.154914.1347048861561693629.davem@davemloft.net>
On Thu, 25 May 2017 15:49:14 -0400 (EDT)
David Miller <davem@davemloft.net> wrote:
> Still not correct, you need to use a "Fixes: " tag of the form:
>
> Fixes: 90427ef5d2a4 ("ipv6: fix flow labels when the traffic class is non-0")
>
> And it must appear of the first line of tags, before signoffs and acks,
> with no empty lines in between.
Here is my proposed commit message in full. Note that
the "Fixes" line extends to 78 chars. Is this OK?
Thanks
This fix addresses two problems in the way the DSCP field is formulated
on the encapsulating header of IPv6 tunnels.
Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=195661
1) The IPv6 tunneling code was manipulating the DSCP field of the
encapsulating packet using the 32b flowlabel. Since the flowlabel is
only the lower 20b it was incorrect to assume that the upper 12b
containing the DSCP and ECN fields would remain intact when formulating
the encapsulating header. This fix handles the 'inherit' and
'fixed-value' DSCP cases explicitly using the extant dsfield u8 variable.
2) The use of INET_ECN_encapsulate(0, dsfield) in ip6_tnl_xmit was
incorrect and resulted in the DSCP value always being set to 0.
Commit 90427ef5d2a4 caused the regression by masking out the flowlabel
which exposed the incorrect the handling of the DSCP portion of the
flowlabel in ip6_tunnel and ip6_gre.
Fixes: 90427ef5d2a4 ("ipv6: fix flow labels when the traffic class is non-0")
Signed-off-by: Peter Dawson <peter.a.dawson@boeing.com>
^ permalink raw reply
* Re: [PATCH net] sky2: Do not deadlock on sky2_hw_down
From: Joshua Emele @ 2017-05-25 20:21 UTC (permalink / raw)
To: Stephen Hemminger; +Cc: netdev, Joshua Emele, Mirko Lindner, linux-kernel
In-Reply-To: <20170525105458.539dedba@xeon-e3>
On Thu, May 25, 2017 at 10:54 AM, Stephen Hemminger
<stephen@networkplumber.org> wrote:
>
> On Wed, 24 May 2017 15:43:18 -0700
> Joshua Emele <jemele@gmail.com> wrote:
>
> > From: Joshua Emele <jemele@google.com>
> >
> > The sky2_hw_down uses sky2_tx_complete to free pending frames stuck in
> > the HW queue. Because sky2_hw_down can be called from a process context,
> > the call to u64_stats_update_begin can result in deadlock.
> >
> > Because the statistics do not require update as part of the sky2_hw_down
> > sequence, prevent the update to avoid the deadlock.
> >
> > [18198.003900] inconsistent {IN-SOFTIRQ-W} -> {SOFTIRQ-ON-W} usage.
> > [18198.009931] ifconfig/11604 [HC0[0]:SC0[0]:HE1:SE1] takes:
> > [18198.015348] (&syncp->seq#2){+.?...}, at: [<805ed440>] sky2_hw_down+0x370/0x428
> > [18198.022827] {IN-SOFTIRQ-W} state was registered at:
> > [18198.027723] [<801729a0>] lock_acquire+0x78/0x98
> > [18198.032484] [<805ed048>] sky2_tx_complete+0x1a8/0x230
> > [18198.037760] [<805f2718>] sky2_poll+0x7cc/0xfa8
> > [18198.042425] [<807692f8>] net_rx_action+0x200/0x330
> > [18198.047447] [<80129f64>] __do_softirq+0x130/0x31c
> > [18198.052369] [<8012a4a0>] irq_exit+0xc8/0x13c
> > [18198.056836] [<8017e398>] __handle_domain_irq+0x84/0xf8
> > [18198.062180] [<80101564>] gic_handle_irq+0x58/0xb8
> > [18198.067086] [<8010d838>] __irq_usr+0x58/0x80
> > [18198.071557] [<76e178ae>] 0x76e178ae
> > [18198.075247] irq event stamp: 2109
> > [18198.078568] hardirqs last enabled at (2109): [<8012a2cc>] __local_bh_enable_ip+0x90/0x110
> > [18198.086860] hardirqs last disabled at (2107): [<8012a27c>] __local_bh_enable_ip+0x40/0x110
> > [18198.095150] softirqs last enabled at (2108): [<805ed368>] sky2_hw_down+0x298/0x428
> > [18198.102832] softirqs last disabled at (2106): [<805ed284>] sky2_hw_down+0x1b4/0x428
> > [18198.110515]
> > other info that might help us debug this:
> > [18198.117048] Possible unsafe locking scenario:
> >
> > [18198.122974] CPU0
> > [18198.125425] ----
> > [18198.127876] lock(&syncp->seq#2);
> > [18198.131332] <Interrupt>
> > [18198.133955] lock(&syncp->seq#2);
> > [18198.137585]
> > *** DEADLOCK ***
> >
> > [18198.143517] 1 lock held by ifconfig/11604:
> > [18198.147618] #0: (rtnl_mutex){+.+.+.}, at: [<8077e874>] rtnl_lock+0x18/0x20
> > [18198.154772]
> > stack backtrace:
> > [18198.159143] CPU: 1 PID: 11604 Comm: ifconfig Not tainted 4.8.17 #1
> > [18198.165331] Hardware name: Freescale i.MX6 Quad/DualLite (Device Tree)
> > [18198.171864] Backtrace:
> > [18198.174353] [<8010c634>] (dump_backtrace) from [<8010c828>] (show_stack+0x18/0x1c)
> > [18198.181931] r6:60070093 r5:00000000 r4:80e23248 r3:00000000
> > [18198.187682] [<8010c810>] (show_stack) from [<8041edc4>] (dump_stack+0xb4/0xe8)
> > [18198.194924] [<8041ed10>] (dump_stack) from [<801700cc>] (print_usage_bug+0x1dc/0x2d0)
> > [18198.202762] r10:edec55c0 r9:80bd1178 r8:81649598 r7:00000006 r6:edec5a90 r5:80fb09f4
> > [18198.210686] r4:edec55c0 r3:00000002
> > [18198.214311] [<8016fef0>] (print_usage_bug) from [<80170348>] (mark_lock+0x188/0x6c4)
> > [18198.222059] r9:00000000 r8:00000004 r7:edec55c0 r6:00000006 r5:edec5a90 r4:8016f44c
> > [18198.229903] [<801701c0>] (mark_lock) from [<801714ac>] (__lock_acquire+0xb90/0x1c70)
> > [18198.237653] r10:edec55c0 r9:00000000 r8:edec5aa4 r7:00000004 r6:00000001 r5:00000000
> > [18198.245573] r4:000001cd r3:00000001
> > [18198.249192] [<8017091c>] (__lock_acquire) from [<801729a0>] (lock_acquire+0x78/0x98)
> > [18198.256940] r10:00000001 r9:000006d0 r8:00000000 r7:00000001 r6:805ed440 r5:60070013
> > [18198.264860] r4:00000000
> > [18198.267428] [<80172928>] (lock_acquire) from [<805ed048>] (sky2_tx_complete+0x1a8/0x230)
> > [18198.275523] r7:ee2d9dfc r6:00000000 r5:ee2d9dc0 r4:00000000
> > [18198.281266] [<805ecea0>] (sky2_tx_complete) from [<805ed440>] (sky2_hw_down+0x370/0x428)
> > [18198.289360] r10:ee2cac00 r9:000006d0 r8:ee2d9dc0 r7:f0d40aa8 r6:00000001 r5:00000d48
> > [18198.297281] r4:00000000
> > [18198.299850] [<805ed0d0>] (sky2_hw_down) from [<805efed8>] (sky2_close+0xac/0x11c)
> > [18198.307337] r10:ee838600 r9:00000000 r8:00000000 r7:00001003 r6:ee2d9dc0 r5:00000000
> > [18198.315258] r4:ee2cac00
> > [18198.317830] [<805efe2c>] (sky2_close) from [<8076a310>] (__dev_close_many+0xc4/0x118)
> > [18198.325664] r7:00001003 r6:00001042 r5:eb047df8 r4:ee2d9800
> > [18198.331404] [<8076a24c>] (__dev_close_many) from [<8076ab24>] (__dev_close+0x30/0x48)
> > [18198.339240] r5:00000001 r4:ee2d9800
> > [18198.342866] [<8076aaf4>] (__dev_close) from [<8076dbac>] (__dev_change_flags+0x90/0x154)
> > [18198.350970] [<8076db1c>] (__dev_change_flags) from [<8076dc90>] (dev_change_flags+0x20/0x50)
> > [18198.359412] r8:00000000 r7:00008914 r6:00001003 r5:ee2d9948 r4:ee2d9800 r3:00000014
> > [18198.367264] [<8076dc70>] (dev_change_flags) from [<807f06d0>] (devinet_ioctl+0x724/0x818)
> > [18198.375448] r8:ffffffff r7:00008914 r6:ee2cae0c r5:7ed799ac r4:eb047e80 r3:00000014
> > [18198.383291] [<807effac>] (devinet_ioctl) from [<807f2e98>] (inet_ioctl+0x19c/0x1c8)
> > [18198.390951] r10:edfc3b80 r9:eb046000 r8:00000004 r7:ee724b40 r6:7ed799ac r5:ee724b60
> > [18198.398872] r4:00008914
> > [18198.401446] [<807f2cfc>] (inet_ioctl) from [<8074a234>] (sock_ioctl+0x158/0x300)
> > [18198.408860] [<8074a0dc>] (sock_ioctl) from [<80239770>] (do_vfs_ioctl+0x98/0xa3c)
> > [18198.416348] r7:8023a150 r6:00000004 r5:ee724b60 r4:7ed799ac
> > [18198.422087] [<802396d8>] (do_vfs_ioctl) from [<8023a150>] (SyS_ioctl+0x3c/0x64)
> > [18198.429401] r10:00000000 r9:eb046000 r8:00000004 r7:00008914 r6:edfc3b80 r5:7ed799ac
> > [18198.437326] r4:edfc3b80
> > [18198.439895] [<8023a114>] (SyS_ioctl) from [<80107ee0>] (ret_fast_syscall+0x0/0x1c)
> > [18198.447469] r8:80108084 r7:00000036 r6:00000004 r5:7ed799ac r4:7ed79b20 r3:31687465
> >
> > Signed-off-by: Joshua Emele <jemele@google.com>
>
> This problem was introduced by the "better version of seqcount". The original
> version which is the raw_XXX version does not have any locking.
>
> Sigh. The point of u64_stats_update_begin/end was that they are supposed to be lock less.
> What architecture are you using that has such a broken version which uses locks?
>
I'm using a Gatework 5304 Ventana, which is an imx6q
(CONFIG_SOC_IMX6Q) single board computer (
http://trac.gateworks.com/wiki/ventana).
^ permalink raw reply
* Re: [PATCH net] ip6_tunnel, ip6_gre: fix setting of DSCP on encapsulated packets
From: David Miller @ 2017-05-25 20:33 UTC (permalink / raw)
To: petedaws; +Cc: kuznet, jmorris, yoshfuji, kaber, stephen, netdev, linux-kernel
In-Reply-To: <20170526060842.4bd21054@udesktop>
From: Peter Dawson <petedaws@gmail.com>
Date: Fri, 26 May 2017 06:08:42 +1000
> On Thu, 25 May 2017 15:49:14 -0400 (EDT)
> David Miller <davem@davemloft.net> wrote:
>
>> Still not correct, you need to use a "Fixes: " tag of the form:
>>
>> Fixes: 90427ef5d2a4 ("ipv6: fix flow labels when the traffic class is non-0")
>>
>> And it must appear of the first line of tags, before signoffs and acks,
>> with no empty lines in between.
>
> Here is my proposed commit message in full. Note that
> the "Fixes" line extends to 78 chars. Is this OK?
Yes, that looks perfect.
^ permalink raw reply
* [PATCH net,v2] ip6_tunnel, ip6_gre: fix setting of DSCP on encapsulated packets
From: Peter Dawson @ 2017-05-25 20:35 UTC (permalink / raw)
To: David S. Miller, Alexey Kuznetsov, James Morris,
Hideaki YOSHIFUJI, Patrick McHardy, stephen, netdev, linux-kernel
In-Reply-To: <20170523143616.38116e8f@gmail.com>
This fix addresses two problems in the way the DSCP field is formulated
on the encapsulating header of IPv6 tunnels.
Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=195661
1) The IPv6 tunneling code was manipulating the DSCP field of the
encapsulating packet using the 32b flowlabel. Since the flowlabel is
only the lower 20b it was incorrect to assume that the upper 12b
containing the DSCP and ECN fields would remain intact when formulating
the encapsulating header. This fix handles the 'inherit' and
'fixed-value' DSCP cases explicitly using the extant dsfield u8 variable.
2) The use of INET_ECN_encapsulate(0, dsfield) in ip6_tnl_xmit was
incorrect and resulted in the DSCP value always being set to 0.
Commit 90427ef5d2a4 ("ipv6: fix flow labels when the traffic class
is non-0") caused the regression by masking out the flowlabel
which exposed the incorrect handling of the DSCP portion of the
flowlabel in ip6_tunnel and ip6_gre.
Fixes: 90427ef5d2a4 ("ipv6: fix flow labels when the traffic class is non-0")
Signed-off-by: Peter Dawson <peter.a.dawson@boeing.com>
---
net/ipv6/ip6_gre.c | 13 +++++++------
net/ipv6/ip6_tunnel.c | 21 +++++++++++++--------
2 files changed, 20 insertions(+), 14 deletions(-)
diff --git a/net/ipv6/ip6_gre.c b/net/ipv6/ip6_gre.c
index 8d128ba..0c5b4caa 100644
--- a/net/ipv6/ip6_gre.c
+++ b/net/ipv6/ip6_gre.c
@@ -537,11 +537,10 @@ static inline int ip6gre_xmit_ipv4(struct sk_buff *skb, struct net_device *dev)
memcpy(&fl6, &t->fl.u.ip6, sizeof(fl6));
- dsfield = ipv4_get_dsfield(iph);
-
if (t->parms.flags & IP6_TNL_F_USE_ORIG_TCLASS)
- fl6.flowlabel |= htonl((__u32)iph->tos << IPV6_TCLASS_SHIFT)
- & IPV6_TCLASS_MASK;
+ dsfield = ipv4_get_dsfield(iph);
+ else
+ dsfield = ip6_tclass(t->parms.flowinfo);
if (t->parms.flags & IP6_TNL_F_USE_ORIG_FWMARK)
fl6.flowi6_mark = skb->mark;
else
@@ -598,9 +597,11 @@ static inline int ip6gre_xmit_ipv6(struct sk_buff *skb, struct net_device *dev)
memcpy(&fl6, &t->fl.u.ip6, sizeof(fl6));
- dsfield = ipv6_get_dsfield(ipv6h);
if (t->parms.flags & IP6_TNL_F_USE_ORIG_TCLASS)
- fl6.flowlabel |= (*(__be32 *) ipv6h & IPV6_TCLASS_MASK);
+ dsfield = ipv6_get_dsfield(ipv6h);
+ else
+ dsfield = ip6_tclass(t->parms.flowinfo);
+
if (t->parms.flags & IP6_TNL_F_USE_ORIG_FLOWLABEL)
fl6.flowlabel |= ip6_flowlabel(ipv6h);
if (t->parms.flags & IP6_TNL_F_USE_ORIG_FWMARK)
diff --git a/net/ipv6/ip6_tunnel.c b/net/ipv6/ip6_tunnel.c
index 6eb2ae5..7ae6c50 100644
--- a/net/ipv6/ip6_tunnel.c
+++ b/net/ipv6/ip6_tunnel.c
@@ -1196,7 +1196,7 @@ int ip6_tnl_xmit(struct sk_buff *skb, struct net_device *dev, __u8 dsfield,
skb_push(skb, sizeof(struct ipv6hdr));
skb_reset_network_header(skb);
ipv6h = ipv6_hdr(skb);
- ip6_flow_hdr(ipv6h, INET_ECN_encapsulate(0, dsfield),
+ ip6_flow_hdr(ipv6h, dsfield,
ip6_make_flowlabel(net, skb, fl6->flowlabel, true, fl6));
ipv6h->hop_limit = hop_limit;
ipv6h->nexthdr = proto;
@@ -1231,8 +1231,6 @@ ip4ip6_tnl_xmit(struct sk_buff *skb, struct net_device *dev)
if (tproto != IPPROTO_IPIP && tproto != 0)
return -1;
- dsfield = ipv4_get_dsfield(iph);
-
if (t->parms.collect_md) {
struct ip_tunnel_info *tun_info;
const struct ip_tunnel_key *key;
@@ -1246,6 +1244,7 @@ ip4ip6_tnl_xmit(struct sk_buff *skb, struct net_device *dev)
fl6.flowi6_proto = IPPROTO_IPIP;
fl6.daddr = key->u.ipv6.dst;
fl6.flowlabel = key->label;
+ dsfield = ip6_tclass(key->label);
} else {
if (!(t->parms.flags & IP6_TNL_F_IGN_ENCAP_LIMIT))
encap_limit = t->parms.encap_limit;
@@ -1254,8 +1253,9 @@ ip4ip6_tnl_xmit(struct sk_buff *skb, struct net_device *dev)
fl6.flowi6_proto = IPPROTO_IPIP;
if (t->parms.flags & IP6_TNL_F_USE_ORIG_TCLASS)
- fl6.flowlabel |= htonl((__u32)iph->tos << IPV6_TCLASS_SHIFT)
- & IPV6_TCLASS_MASK;
+ dsfield = ipv4_get_dsfield(iph);
+ else
+ dsfield = ip6_tclass(t->parms.flowinfo);
if (t->parms.flags & IP6_TNL_F_USE_ORIG_FWMARK)
fl6.flowi6_mark = skb->mark;
else
@@ -1267,6 +1267,8 @@ ip4ip6_tnl_xmit(struct sk_buff *skb, struct net_device *dev)
if (iptunnel_handle_offloads(skb, SKB_GSO_IPXIP6))
return -1;
+ dsfield = INET_ECN_encapsulate(dsfield, ipv4_get_dsfield(iph));
+
skb_set_inner_ipproto(skb, IPPROTO_IPIP);
err = ip6_tnl_xmit(skb, dev, dsfield, &fl6, encap_limit, &mtu,
@@ -1300,8 +1302,6 @@ ip6ip6_tnl_xmit(struct sk_buff *skb, struct net_device *dev)
ip6_tnl_addr_conflict(t, ipv6h))
return -1;
- dsfield = ipv6_get_dsfield(ipv6h);
-
if (t->parms.collect_md) {
struct ip_tunnel_info *tun_info;
const struct ip_tunnel_key *key;
@@ -1315,6 +1315,7 @@ ip6ip6_tnl_xmit(struct sk_buff *skb, struct net_device *dev)
fl6.flowi6_proto = IPPROTO_IPV6;
fl6.daddr = key->u.ipv6.dst;
fl6.flowlabel = key->label;
+ dsfield = ip6_tclass(key->label);
} else {
offset = ip6_tnl_parse_tlv_enc_lim(skb, skb_network_header(skb));
/* ip6_tnl_parse_tlv_enc_lim() might have reallocated skb->head */
@@ -1337,7 +1338,9 @@ ip6ip6_tnl_xmit(struct sk_buff *skb, struct net_device *dev)
fl6.flowi6_proto = IPPROTO_IPV6;
if (t->parms.flags & IP6_TNL_F_USE_ORIG_TCLASS)
- fl6.flowlabel |= (*(__be32 *)ipv6h & IPV6_TCLASS_MASK);
+ dsfield = ipv6_get_dsfield(ipv6h);
+ else
+ dsfield = ip6_tclass(t->parms.flowinfo);
if (t->parms.flags & IP6_TNL_F_USE_ORIG_FLOWLABEL)
fl6.flowlabel |= ip6_flowlabel(ipv6h);
if (t->parms.flags & IP6_TNL_F_USE_ORIG_FWMARK)
@@ -1351,6 +1354,8 @@ ip6ip6_tnl_xmit(struct sk_buff *skb, struct net_device *dev)
if (iptunnel_handle_offloads(skb, SKB_GSO_IPXIP6))
return -1;
+ dsfield = INET_ECN_encapsulate(dsfield, ipv6_get_dsfield(ipv6h));
+
skb_set_inner_ipproto(skb, IPPROTO_IPV6);
err = ip6_tnl_xmit(skb, dev, dsfield, &fl6, encap_limit, &mtu,
--
2.7.4
^ permalink raw reply related
* Re: [for-next 4/6] net/mlx5: FPGA, Add basic support for Innova
From: Jes Sorensen @ 2017-05-25 20:48 UTC (permalink / raw)
To: Saeed Mahameed, Ilan Tayari
Cc: Alexei Starovoitov, Saeed Mahameed, David S. Miller, Doug Ledford,
netdev-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
linux-rdma-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
In-Reply-To: <CALzJLG-B_tAmASn_SMmPNiucq-tTpywHniRTkb4N32oGF6Y3Ng-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
On 05/25/2017 06:40 AM, Saeed Mahameed wrote:
> On Thu, May 25, 2017 at 8:20 AM, Ilan Tayari <ilant-VPRAkNaXOzVWk0Htik3J/w@public.gmane.org> wrote:
>>> -----Original Message-----
>>> Can you put it into different driver? Dumping everything into by far
>>> the biggest nic driver already is already huge headache in terms on
>>> maintainability, debugging and back ports.
>>> Look at how intel splits their drivers.
>>> ixgb, ixgbe, ixgbevf are different drivers thought they have a lot in
>>> common. On one side it's a bit of copy paste, but on the other side
>
> I don't think the ixgb example is the same, simply ixgb, ixgbe,
> ixgbevf have different PCI IDs
> and even different SW/FW interfaces. On the other hand, same mlx5
> driver can support all of
> ConnetX4/5/6 device IDs with the same code flows, same interfaces.
>
>>> it makes drivers much easier to develop and maintain independently.
>>> ConnectX-6 code and any future hw support doesn't belong to
>>> mlx5 driver at all.
>
> Sorry i must disagree with you on this for the same reasons Ilan mentioned.
> We can perfectly achieve the same with modular driver design all under the
> same .ko module, with some kconfig flags to reduce the amount of code/features
> this .ko provides.
If I get this right, the FPGA is independent and could in theory be used
for non network stuff. It really should have it's own driver in that
case, and you should provide accessor functionality via the mlx5 driver.
We have this with other devices in the kernel where a primary device
driver provides an interface for an additional sub-driver to access
another device behind it. Like bt-coexist in some of the wifi drivers
allowing access to a bluetooth device behind it.
Jes
--
To unsubscribe from this list: send the line "unsubscribe linux-rdma" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* [PATCH net] net: ethernet: ax88796: don't call free_irq without request_irq first
From: Uwe Kleine-König @ 2017-05-25 20:54 UTC (permalink / raw)
To: David S. Miller; +Cc: netdev, kernel, Ben Dooks
The function ax_init_dev (which is called only from the driver's .probe
function) calls free_irq in the error path without having requested the
irq in the first place. So drop the free_irq call in the error path.
Fixes: 825a2ff1896e ("AX88796 network driver")
Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
---
drivers/net/ethernet/8390/ax88796.c | 7 ++-----
1 file changed, 2 insertions(+), 5 deletions(-)
diff --git a/drivers/net/ethernet/8390/ax88796.c b/drivers/net/ethernet/8390/ax88796.c
index b0a3b85fc6f8..db02bc2fb4b2 100644
--- a/drivers/net/ethernet/8390/ax88796.c
+++ b/drivers/net/ethernet/8390/ax88796.c
@@ -748,13 +748,13 @@ static int ax_init_dev(struct net_device *dev)
ret = ax_mii_init(dev);
if (ret)
- goto out_irq;
+ goto err_out;
ax_NS8390_init(dev, 0);
ret = register_netdev(dev);
if (ret)
- goto out_irq;
+ goto err_out;
netdev_info(dev, "%dbit, irq %d, %lx, MAC: %pM\n",
ei_local->word16 ? 16 : 8, dev->irq, dev->base_addr,
@@ -762,9 +762,6 @@ static int ax_init_dev(struct net_device *dev)
return 0;
- out_irq:
- /* cleanup irq */
- free_irq(dev->irq, dev);
err_out:
return ret;
}
--
2.11.0
^ permalink raw reply related
* [PATCH net-next] net: ethernet: ax88796: support generating a random mac address
From: Uwe Kleine-König @ 2017-05-25 20:55 UTC (permalink / raw)
To: David S. Miller; +Cc: netdev, kernel
Instead of falling back to 00:00:00:00:00:00 generate a random address
if none is provided via platform data or from the the device's register
space.
Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
---
drivers/net/ethernet/8390/ax88796.c | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/drivers/net/ethernet/8390/ax88796.c b/drivers/net/ethernet/8390/ax88796.c
index db02bc2fb4b2..05d9d3e2e92e 100644
--- a/drivers/net/ethernet/8390/ax88796.c
+++ b/drivers/net/ethernet/8390/ax88796.c
@@ -723,6 +723,12 @@ static int ax_init_dev(struct net_device *dev)
ax->plat->mac_addr)
memcpy(dev->dev_addr, ax->plat->mac_addr, ETH_ALEN);
+ if (!is_valid_ether_addr(dev->dev_addr)) {
+ eth_hw_addr_random(dev);
+ dev_info(&dev->dev, "Using random MAC address: %pM\n",
+ dev->dev_addr);
+ }
+
ax_reset_8390(dev);
ei_local->name = "AX88796";
--
2.11.0
^ permalink raw reply related
* Re: [PATCH net-next] net: ethernet: ax88796: support generating a random mac address
From: Uwe Kleine-König @ 2017-05-25 20:57 UTC (permalink / raw)
To: David S. Miller; +Cc: netdev, kernel
In-Reply-To: <20170525205511.22048-1-u.kleine-koenig@pengutronix.de>
Hello David,
On Thu, May 25, 2017 at 10:55:11PM +0200, Uwe Kleine-König wrote:
> Instead of falling back to 00:00:00:00:00:00 generate a random address
> if none is provided via platform data or from the the device's register
s/the the/the/
should I resend for this, or can you fixup at commit time (assuming this
patch is ok).
Best regards
Uwe
--
Pengutronix e.K. | Uwe Kleine-König |
Industrial Linux Solutions | http://www.pengutronix.de/ |
^ permalink raw reply
* Re: [PATCH net-next] net: ethernet: ax88796: support generating a random mac address
From: David Miller @ 2017-05-25 21:01 UTC (permalink / raw)
To: u.kleine-koenig; +Cc: netdev, kernel
In-Reply-To: <20170525205741.yoyiszdgchqcnqp2@pengutronix.de>
From: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
Date: Thu, 25 May 2017 22:57:41 +0200
> Hello David,
>
> On Thu, May 25, 2017 at 10:55:11PM +0200, Uwe Kleine-König wrote:
>> Instead of falling back to 00:00:00:00:00:00 generate a random address
>> if none is provided via platform data or from the the device's register
>
> s/the the/the/
>
> should I resend for this, or can you fixup at commit time (assuming this
> patch is ok).
I can fix that up.
^ permalink raw reply
* Re: [PATCH net-next] net: ethernet: ax88796: support generating a random mac address
From: Andrew Lunn @ 2017-05-25 21:25 UTC (permalink / raw)
To: Uwe Kleine-König; +Cc: David S. Miller, netdev, kernel
In-Reply-To: <20170525205511.22048-1-u.kleine-koenig@pengutronix.de>
On Thu, May 25, 2017 at 10:55:11PM +0200, Uwe Kleine-König wrote:
> Instead of falling back to 00:00:00:00:00:00 generate a random address
> if none is provided via platform data or from the the device's register
> space.
>
> Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
Reviewed-by: Andrew Lunn <andrew@lunn.ch>
Andrew
^ permalink raw reply
* [PATCH net] ipv4: add reference counting to metrics
From: Eric Dumazet @ 2017-05-25 21:27 UTC (permalink / raw)
To: David Miller
Cc: Eric Dumazet, Andrey Konovalov, Julian Anastasov, Cong Wang,
netdev
In-Reply-To: <1495665921.6465.95.camel@edumazet-glaptop3.roam.corp.google.com>
From: Eric Dumazet <edumazet@google.com>
Andrey Konovalov reported crashes in ipv4_mtu()
I could reproduce the issue with KASAN kernels, between
10.246.7.151 and 10.246.7.152 :
1) 20 concurrent netperf -t TCP_RR -H 10.246.7.152 -l 1000 &
2) At the same time run following loop :
while :
do
ip ro add 10.246.7.152 dev eth0 src 10.246.7.151 mtu 1500
ip ro del 10.246.7.152 dev eth0 src 10.246.7.151 mtu 1500
done
Cong Wang attempted to add back rt->fi in commit
82486aa6f1b9 ("ipv4: restore rt->fi for reference counting")
but this proved to add some issues that were complex to solve.
Instead, I suggested to add a refcount to the metrics themselves,
being a standalone object (in particular, no reference to other objects)
I tried to make this patch as small as possible to ease its backport,
instead of being super clean. Note that we believe that only ipv4 dst
need to take care of the metric refcount. But if this is wrong,
this patch adds the basic infrastructure to extend this to other
families.
Many thanks to Julian Anastasov for reviewing this patch, and Cong Wang
for his efforts on this problem.
Fixes: 2860583fe840 ("ipv4: Kill rt->fi")
Signed-off-by: Eric Dumazet <edumazet@google.com>
Reported-by: Andrey Konovalov <andreyknvl@google.com>
---
include/net/dst.h | 8 +++++++-
include/net/ip_fib.h | 10 +++++-----
net/core/dst.c | 23 ++++++++++++++---------
net/ipv4/fib_semantics.c | 17 ++++++++++-------
net/ipv4/route.c | 10 +++++++++-
5 files changed, 45 insertions(+), 23 deletions(-)
diff --git a/include/net/dst.h b/include/net/dst.h
index 049af33da3b6c95897d544670cea65c542317673..cfc0437841665d7ed46a714915c50d723c24901c 100644
--- a/include/net/dst.h
+++ b/include/net/dst.h
@@ -107,10 +107,16 @@ struct dst_entry {
};
};
+struct dst_metrics {
+ u32 metrics[RTAX_MAX];
+ atomic_t refcnt;
+};
+extern const struct dst_metrics dst_default_metrics;
+
u32 *dst_cow_metrics_generic(struct dst_entry *dst, unsigned long old);
-extern const u32 dst_default_metrics[];
#define DST_METRICS_READ_ONLY 0x1UL
+#define DST_METRICS_REFCOUNTED 0x2UL
#define DST_METRICS_FLAGS 0x3UL
#define __DST_METRICS_PTR(Y) \
((u32 *)((Y) & ~DST_METRICS_FLAGS))
diff --git a/include/net/ip_fib.h b/include/net/ip_fib.h
index 6692c5758b332d468f1e0611ecc4f3e03ae03b2b..f7f6aa789c6174c41ca9739206d586c559c1f3a1 100644
--- a/include/net/ip_fib.h
+++ b/include/net/ip_fib.h
@@ -114,11 +114,11 @@ struct fib_info {
__be32 fib_prefsrc;
u32 fib_tb_id;
u32 fib_priority;
- u32 *fib_metrics;
-#define fib_mtu fib_metrics[RTAX_MTU-1]
-#define fib_window fib_metrics[RTAX_WINDOW-1]
-#define fib_rtt fib_metrics[RTAX_RTT-1]
-#define fib_advmss fib_metrics[RTAX_ADVMSS-1]
+ struct dst_metrics *fib_metrics;
+#define fib_mtu fib_metrics->metrics[RTAX_MTU-1]
+#define fib_window fib_metrics->metrics[RTAX_WINDOW-1]
+#define fib_rtt fib_metrics->metrics[RTAX_RTT-1]
+#define fib_advmss fib_metrics->metrics[RTAX_ADVMSS-1]
int fib_nhs;
#ifdef CONFIG_IP_ROUTE_MULTIPATH
int fib_weight;
diff --git a/net/core/dst.c b/net/core/dst.c
index 960e503b5a529a2c4f1866f49c150493ee98d7da..6192f11beec9077de964e2aeff4f78547f08b8da 100644
--- a/net/core/dst.c
+++ b/net/core/dst.c
@@ -151,13 +151,13 @@ int dst_discard_out(struct net *net, struct sock *sk, struct sk_buff *skb)
}
EXPORT_SYMBOL(dst_discard_out);
-const u32 dst_default_metrics[RTAX_MAX + 1] = {
+const struct dst_metrics dst_default_metrics = {
/* This initializer is needed to force linker to place this variable
* into const section. Otherwise it might end into bss section.
* We really want to avoid false sharing on this variable, and catch
* any writes on it.
*/
- [RTAX_MAX] = 0xdeadbeef,
+ .refcnt = ATOMIC_INIT(1),
};
void dst_init(struct dst_entry *dst, struct dst_ops *ops,
@@ -169,7 +169,7 @@ void dst_init(struct dst_entry *dst, struct dst_ops *ops,
if (dev)
dev_hold(dev);
dst->ops = ops;
- dst_init_metrics(dst, dst_default_metrics, true);
+ dst_init_metrics(dst, dst_default_metrics.metrics, true);
dst->expires = 0UL;
dst->path = dst;
dst->from = NULL;
@@ -314,25 +314,30 @@ EXPORT_SYMBOL(dst_release);
u32 *dst_cow_metrics_generic(struct dst_entry *dst, unsigned long old)
{
- u32 *p = kmalloc(sizeof(u32) * RTAX_MAX, GFP_ATOMIC);
+ struct dst_metrics *p = kmalloc(sizeof(*p), GFP_ATOMIC);
if (p) {
- u32 *old_p = __DST_METRICS_PTR(old);
+ struct dst_metrics *old_p = (struct dst_metrics *)__DST_METRICS_PTR(old);
unsigned long prev, new;
- memcpy(p, old_p, sizeof(u32) * RTAX_MAX);
+ atomic_set(&p->refcnt, 1);
+ memcpy(p->metrics, old_p->metrics, sizeof(p->metrics));
new = (unsigned long) p;
prev = cmpxchg(&dst->_metrics, old, new);
if (prev != old) {
kfree(p);
- p = __DST_METRICS_PTR(prev);
+ p = (struct dst_metrics *)__DST_METRICS_PTR(prev);
if (prev & DST_METRICS_READ_ONLY)
p = NULL;
+ } else if (prev & DST_METRICS_REFCOUNTED) {
+ if (atomic_dec_and_test(&old_p->refcnt))
+ kfree(old_p);
}
}
- return p;
+ BUILD_BUG_ON(offsetof(struct dst_metrics, metrics) != 0);
+ return (u32 *)p;
}
EXPORT_SYMBOL(dst_cow_metrics_generic);
@@ -341,7 +346,7 @@ void __dst_destroy_metrics_generic(struct dst_entry *dst, unsigned long old)
{
unsigned long prev, new;
- new = ((unsigned long) dst_default_metrics) | DST_METRICS_READ_ONLY;
+ new = ((unsigned long) &dst_default_metrics) | DST_METRICS_READ_ONLY;
prev = cmpxchg(&dst->_metrics, old, new);
if (prev == old)
kfree(__DST_METRICS_PTR(old));
diff --git a/net/ipv4/fib_semantics.c b/net/ipv4/fib_semantics.c
index da449ddb8cc172bd9091c00057a69a095f98b56d..ad9ad4aab5da7c7d11c3b80edbdfcbdd3d7153fe 100644
--- a/net/ipv4/fib_semantics.c
+++ b/net/ipv4/fib_semantics.c
@@ -203,6 +203,7 @@ static void rt_fibinfo_free_cpus(struct rtable __rcu * __percpu *rtp)
static void free_fib_info_rcu(struct rcu_head *head)
{
struct fib_info *fi = container_of(head, struct fib_info, rcu);
+ struct dst_metrics *m;
change_nexthops(fi) {
if (nexthop_nh->nh_dev)
@@ -213,8 +214,9 @@ static void free_fib_info_rcu(struct rcu_head *head)
rt_fibinfo_free(&nexthop_nh->nh_rth_input);
} endfor_nexthops(fi);
- if (fi->fib_metrics != (u32 *) dst_default_metrics)
- kfree(fi->fib_metrics);
+ m = fi->fib_metrics;
+ if (m != &dst_default_metrics && atomic_dec_and_test(&m->refcnt))
+ kfree(m);
kfree(fi);
}
@@ -971,11 +973,11 @@ fib_convert_metrics(struct fib_info *fi, const struct fib_config *cfg)
val = 255;
if (type == RTAX_FEATURES && (val & ~RTAX_FEATURE_MASK))
return -EINVAL;
- fi->fib_metrics[type - 1] = val;
+ fi->fib_metrics->metrics[type - 1] = val;
}
if (ecn_ca)
- fi->fib_metrics[RTAX_FEATURES - 1] |= DST_FEATURE_ECN_CA;
+ fi->fib_metrics->metrics[RTAX_FEATURES - 1] |= DST_FEATURE_ECN_CA;
return 0;
}
@@ -1033,11 +1035,12 @@ struct fib_info *fib_create_info(struct fib_config *cfg)
goto failure;
fib_info_cnt++;
if (cfg->fc_mx) {
- fi->fib_metrics = kzalloc(sizeof(u32) * RTAX_MAX, GFP_KERNEL);
+ fi->fib_metrics = kzalloc(sizeof(*fi->fib_metrics), GFP_KERNEL);
if (!fi->fib_metrics)
goto failure;
+ atomic_set(&fi->fib_metrics->refcnt, 1);
} else
- fi->fib_metrics = (u32 *) dst_default_metrics;
+ fi->fib_metrics = (struct dst_metrics *)&dst_default_metrics;
fi->fib_net = net;
fi->fib_protocol = cfg->fc_protocol;
@@ -1238,7 +1241,7 @@ int fib_dump_info(struct sk_buff *skb, u32 portid, u32 seq, int event,
if (fi->fib_priority &&
nla_put_u32(skb, RTA_PRIORITY, fi->fib_priority))
goto nla_put_failure;
- if (rtnetlink_put_metrics(skb, fi->fib_metrics) < 0)
+ if (rtnetlink_put_metrics(skb, fi->fib_metrics->metrics) < 0)
goto nla_put_failure;
if (fi->fib_prefsrc &&
diff --git a/net/ipv4/route.c b/net/ipv4/route.c
index 655d9eebe43e16a59102edcd3ea4bc177c6b341d..6883b3d4ba8f69de2cb924612d60f5671a219a84 100644
--- a/net/ipv4/route.c
+++ b/net/ipv4/route.c
@@ -1385,8 +1385,12 @@ static void rt_add_uncached_list(struct rtable *rt)
static void ipv4_dst_destroy(struct dst_entry *dst)
{
+ struct dst_metrics *p = (struct dst_metrics *)DST_METRICS_PTR(dst);
struct rtable *rt = (struct rtable *) dst;
+ if (p != &dst_default_metrics && atomic_dec_and_test(&p->refcnt))
+ kfree(p);
+
if (!list_empty(&rt->rt_uncached)) {
struct uncached_list *ul = rt->rt_uncached_list;
@@ -1438,7 +1442,11 @@ static void rt_set_nexthop(struct rtable *rt, __be32 daddr,
rt->rt_gateway = nh->nh_gw;
rt->rt_uses_gateway = 1;
}
- dst_init_metrics(&rt->dst, fi->fib_metrics, true);
+ dst_init_metrics(&rt->dst, fi->fib_metrics->metrics, true);
+ if (fi->fib_metrics != &dst_default_metrics) {
+ rt->dst._metrics |= DST_METRICS_REFCOUNTED;
+ atomic_inc(&fi->fib_metrics->refcnt);
+ }
#ifdef CONFIG_IP_ROUTE_CLASSID
rt->dst.tclassid = nh->nh_tclassid;
#endif
^ permalink raw reply related
* Re: [PATCH net] sky2: Do not deadlock on sky2_hw_down
From: Stephen Hemminger @ 2017-05-25 22:05 UTC (permalink / raw)
To: Joshua Emele; +Cc: jemele, netdev, Joshua Emele, Mirko Lindner, linux-kernel
In-Reply-To: <CALH_86T3YW=VOCACJ+659GxZQQLtVafRpUTqQagWUdcsPDPH=A@mail.gmail.com>
On Thu, 25 May 2017 13:21:58 -0700
Joshua Emele <jemele@gmail.com> wrote:
> On Thu, May 25, 2017 at 10:54 AM, Stephen Hemminger
> <stephen@networkplumber.org> wrote:
> >
> > On Wed, 24 May 2017 15:43:18 -0700
> > Joshua Emele <jemele@gmail.com> wrote:
> >
> > > From: Joshua Emele <jemele@google.com>
> > >
> > > The sky2_hw_down uses sky2_tx_complete to free pending frames stuck in
> > > the HW queue. Because sky2_hw_down can be called from a process context,
> > > the call to u64_stats_update_begin can result in deadlock.
> > >
> > > Because the statistics do not require update as part of the sky2_hw_down
> > > sequence, prevent the update to avoid the deadlock.
> > >
> > > [18198.003900] inconsistent {IN-SOFTIRQ-W} -> {SOFTIRQ-ON-W} usage.
> > > [18198.009931] ifconfig/11604 [HC0[0]:SC0[0]:HE1:SE1] takes:
> > > [18198.015348] (&syncp->seq#2){+.?...}, at: [<805ed440>] sky2_hw_down+0x370/0x428
> > > [18198.022827] {IN-SOFTIRQ-W} state was registered at:
> > > [18198.027723] [<801729a0>] lock_acquire+0x78/0x98
> > > [18198.032484] [<805ed048>] sky2_tx_complete+0x1a8/0x230
> > > [18198.037760] [<805f2718>] sky2_poll+0x7cc/0xfa8
> > > [18198.042425] [<807692f8>] net_rx_action+0x200/0x330
> > > [18198.047447] [<80129f64>] __do_softirq+0x130/0x31c
> > > [18198.052369] [<8012a4a0>] irq_exit+0xc8/0x13c
> > > [18198.056836] [<8017e398>] __handle_domain_irq+0x84/0xf8
> > > [18198.062180] [<80101564>] gic_handle_irq+0x58/0xb8
> > > [18198.067086] [<8010d838>] __irq_usr+0x58/0x80
> > > [18198.071557] [<76e178ae>] 0x76e178ae
> > > [18198.075247] irq event stamp: 2109
> > > [18198.078568] hardirqs last enabled at (2109): [<8012a2cc>] __local_bh_enable_ip+0x90/0x110
> > > [18198.086860] hardirqs last disabled at (2107): [<8012a27c>] __local_bh_enable_ip+0x40/0x110
> > > [18198.095150] softirqs last enabled at (2108): [<805ed368>] sky2_hw_down+0x298/0x428
> > > [18198.102832] softirqs last disabled at (2106): [<805ed284>] sky2_hw_down+0x1b4/0x428
> > > [18198.110515]
> > > other info that might help us debug this:
> > > [18198.117048] Possible unsafe locking scenario:
> > >
> > > [18198.122974] CPU0
> > > [18198.125425] ----
> > > [18198.127876] lock(&syncp->seq#2);
> > > [18198.131332] <Interrupt>
> > > [18198.133955] lock(&syncp->seq#2);
> > > [18198.137585]
> > > *** DEADLOCK ***
> > >
> > > [18198.143517] 1 lock held by ifconfig/11604:
> > > [18198.147618] #0: (rtnl_mutex){+.+.+.}, at: [<8077e874>] rtnl_lock+0x18/0x20
> > > [18198.154772]
> > > stack backtrace:
> > > [18198.159143] CPU: 1 PID: 11604 Comm: ifconfig Not tainted 4.8.17 #1
> > > [18198.165331] Hardware name: Freescale i.MX6 Quad/DualLite (Device Tree)
> > > [18198.171864] Backtrace:
> > > [18198.174353] [<8010c634>] (dump_backtrace) from [<8010c828>] (show_stack+0x18/0x1c)
> > > [18198.181931] r6:60070093 r5:00000000 r4:80e23248 r3:00000000
> > > [18198.187682] [<8010c810>] (show_stack) from [<8041edc4>] (dump_stack+0xb4/0xe8)
> > > [18198.194924] [<8041ed10>] (dump_stack) from [<801700cc>] (print_usage_bug+0x1dc/0x2d0)
> > > [18198.202762] r10:edec55c0 r9:80bd1178 r8:81649598 r7:00000006 r6:edec5a90 r5:80fb09f4
> > > [18198.210686] r4:edec55c0 r3:00000002
> > > [18198.214311] [<8016fef0>] (print_usage_bug) from [<80170348>] (mark_lock+0x188/0x6c4)
> > > [18198.222059] r9:00000000 r8:00000004 r7:edec55c0 r6:00000006 r5:edec5a90 r4:8016f44c
> > > [18198.229903] [<801701c0>] (mark_lock) from [<801714ac>] (__lock_acquire+0xb90/0x1c70)
> > > [18198.237653] r10:edec55c0 r9:00000000 r8:edec5aa4 r7:00000004 r6:00000001 r5:00000000
> > > [18198.245573] r4:000001cd r3:00000001
> > > [18198.249192] [<8017091c>] (__lock_acquire) from [<801729a0>] (lock_acquire+0x78/0x98)
> > > [18198.256940] r10:00000001 r9:000006d0 r8:00000000 r7:00000001 r6:805ed440 r5:60070013
> > > [18198.264860] r4:00000000
> > > [18198.267428] [<80172928>] (lock_acquire) from [<805ed048>] (sky2_tx_complete+0x1a8/0x230)
> > > [18198.275523] r7:ee2d9dfc r6:00000000 r5:ee2d9dc0 r4:00000000
> > > [18198.281266] [<805ecea0>] (sky2_tx_complete) from [<805ed440>] (sky2_hw_down+0x370/0x428)
> > > [18198.289360] r10:ee2cac00 r9:000006d0 r8:ee2d9dc0 r7:f0d40aa8 r6:00000001 r5:00000d48
> > > [18198.297281] r4:00000000
> > > [18198.299850] [<805ed0d0>] (sky2_hw_down) from [<805efed8>] (sky2_close+0xac/0x11c)
> > > [18198.307337] r10:ee838600 r9:00000000 r8:00000000 r7:00001003 r6:ee2d9dc0 r5:00000000
> > > [18198.315258] r4:ee2cac00
> > > [18198.317830] [<805efe2c>] (sky2_close) from [<8076a310>] (__dev_close_many+0xc4/0x118)
> > > [18198.325664] r7:00001003 r6:00001042 r5:eb047df8 r4:ee2d9800
> > > [18198.331404] [<8076a24c>] (__dev_close_many) from [<8076ab24>] (__dev_close+0x30/0x48)
> > > [18198.339240] r5:00000001 r4:ee2d9800
> > > [18198.342866] [<8076aaf4>] (__dev_close) from [<8076dbac>] (__dev_change_flags+0x90/0x154)
> > > [18198.350970] [<8076db1c>] (__dev_change_flags) from [<8076dc90>] (dev_change_flags+0x20/0x50)
> > > [18198.359412] r8:00000000 r7:00008914 r6:00001003 r5:ee2d9948 r4:ee2d9800 r3:00000014
> > > [18198.367264] [<8076dc70>] (dev_change_flags) from [<807f06d0>] (devinet_ioctl+0x724/0x818)
> > > [18198.375448] r8:ffffffff r7:00008914 r6:ee2cae0c r5:7ed799ac r4:eb047e80 r3:00000014
> > > [18198.383291] [<807effac>] (devinet_ioctl) from [<807f2e98>] (inet_ioctl+0x19c/0x1c8)
> > > [18198.390951] r10:edfc3b80 r9:eb046000 r8:00000004 r7:ee724b40 r6:7ed799ac r5:ee724b60
> > > [18198.398872] r4:00008914
> > > [18198.401446] [<807f2cfc>] (inet_ioctl) from [<8074a234>] (sock_ioctl+0x158/0x300)
> > > [18198.408860] [<8074a0dc>] (sock_ioctl) from [<80239770>] (do_vfs_ioctl+0x98/0xa3c)
> > > [18198.416348] r7:8023a150 r6:00000004 r5:ee724b60 r4:7ed799ac
> > > [18198.422087] [<802396d8>] (do_vfs_ioctl) from [<8023a150>] (SyS_ioctl+0x3c/0x64)
> > > [18198.429401] r10:00000000 r9:eb046000 r8:00000004 r7:00008914 r6:edfc3b80 r5:7ed799ac
> > > [18198.437326] r4:edfc3b80
> > > [18198.439895] [<8023a114>] (SyS_ioctl) from [<80107ee0>] (ret_fast_syscall+0x0/0x1c)
> > > [18198.447469] r8:80108084 r7:00000036 r6:00000004 r5:7ed799ac r4:7ed79b20 r3:31687465
> > >
> > > Signed-off-by: Joshua Emele <jemele@google.com>
> >
> > This problem was introduced by the "better version of seqcount". The original
> > version which is the raw_XXX version does not have any locking.
> >
> > Sigh. The point of u64_stats_update_begin/end was that they are supposed to be lock less.
> > What architecture are you using that has such a broken version which uses locks?
> >
>
> I'm using a Gatework 5304 Ventana, which is an imx6q
> (CONFIG_SOC_IMX6Q) single board computer (
> http://trac.gateworks.com/wiki/ventana).
Ok, the issue is that lockdep is being stupid and thinking that seqcount's behave
like locks. Maybe something like:
Subject: [PATCH] sky2: use raw seqcount for statistics update
Lockdep generates false complaints because it doesn't think of
seqcount update as non-locking. Fix it in sky2 but probably
should be done in general across all networking.
Signed-off-by: Stephen Hemminger <sthemmin@microsoft.com>
---
drivers/net/ethernet/marvell/sky2.c | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/drivers/net/ethernet/marvell/sky2.c b/drivers/net/ethernet/marvell/sky2.c
index 1145cde2274a..bb8d0b682447 100644
--- a/drivers/net/ethernet/marvell/sky2.c
+++ b/drivers/net/ethernet/marvell/sky2.c
@@ -2046,10 +2046,10 @@ static void sky2_tx_complete(struct sky2_port *sky2, u16 done)
netdev_completed_queue(dev, pkts_compl, bytes_compl);
- u64_stats_update_begin(&sky2->tx_stats.syncp);
+ u64_stats_update_begin_raw(&sky2->tx_stats.syncp);
sky2->tx_stats.packets += pkts_compl;
sky2->tx_stats.bytes += bytes_compl;
- u64_stats_update_end(&sky2->tx_stats.syncp);
+ u64_stats_update_end_raw(&sky2->tx_stats.syncp);
}
static void sky2_tx_reset(struct sky2_hw *hw, unsigned port)
@@ -2661,10 +2661,10 @@ static inline void sky2_rx_done(struct sky2_hw *hw, unsigned port,
if (packets == 0)
return;
- u64_stats_update_begin(&sky2->rx_stats.syncp);
+ u64_stats_update_begin_raw(&sky2->rx_stats.syncp);
sky2->rx_stats.packets += packets;
sky2->rx_stats.bytes += bytes;
- u64_stats_update_end(&sky2->rx_stats.syncp);
+ u64_stats_update_end_raw(&sky2->rx_stats.syncp);
sky2->last_rx = jiffies;
sky2_rx_update(netdev_priv(dev), rxqaddr[port]);
--
2.11.0
^ permalink raw reply related
* Re: [PATCH net] sky2: Do not deadlock on sky2_hw_down
From: Francois Romieu @ 2017-05-25 22:05 UTC (permalink / raw)
To: David Miller; +Cc: jemele, netdev, jemele, mlindner, stephen, linux-kernel
In-Reply-To: <20170525.134205.884395652948196578.davem@davemloft.net>
David Miller <davem@davemloft.net> :
> From: Joshua Emele <jemele@gmail.com>
> Date: Wed, 24 May 2017 15:43:18 -0700
[...]
> > The sky2_hw_down uses sky2_tx_complete to free pending frames stuck in
> > the HW queue. Because sky2_hw_down can be called from a process context,
> > the call to u64_stats_update_begin can result in deadlock.
> >
> > Because the statistics do not require update as part of the sky2_hw_down
> > sequence, prevent the update to avoid the deadlock.
>
> I disagree. Taking the interface down should cause events in the
> statistics to be lost.
>
> You're going to have to find a way to fix this without eliding
> the stats increments.
NAPI processing is already disabled at this stage in the device close()
path (and sky2_netpoll() uses napi_schedule).
It's possible to add a conditionnal bh or irq disabling instruction to
silent the warning but it should not be needed at all.
--
Ueimor
^ permalink raw reply
* Re: [PATCH net] ipv4: add reference counting to metrics
From: Julian Anastasov @ 2017-05-25 22:25 UTC (permalink / raw)
To: Eric Dumazet
Cc: David Miller, Eric Dumazet, Andrey Konovalov, Cong Wang, netdev
In-Reply-To: <1495747655.6465.113.camel@edumazet-glaptop3.roam.corp.google.com>
Hello,
On Thu, 25 May 2017, Eric Dumazet wrote:
> From: Eric Dumazet <edumazet@google.com>
>
> Andrey Konovalov reported crashes in ipv4_mtu()
>
> I could reproduce the issue with KASAN kernels, between
> 10.246.7.151 and 10.246.7.152 :
>
> 1) 20 concurrent netperf -t TCP_RR -H 10.246.7.152 -l 1000 &
>
> 2) At the same time run following loop :
> while :
> do
> ip ro add 10.246.7.152 dev eth0 src 10.246.7.151 mtu 1500
> ip ro del 10.246.7.152 dev eth0 src 10.246.7.151 mtu 1500
> done
>
>
> Cong Wang attempted to add back rt->fi in commit
> 82486aa6f1b9 ("ipv4: restore rt->fi for reference counting")
> but this proved to add some issues that were complex to solve.
>
> Instead, I suggested to add a refcount to the metrics themselves,
> being a standalone object (in particular, no reference to other objects)
>
> I tried to make this patch as small as possible to ease its backport,
> instead of being super clean. Note that we believe that only ipv4 dst
> need to take care of the metric refcount. But if this is wrong,
> this patch adds the basic infrastructure to extend this to other
> families.
>
> Many thanks to Julian Anastasov for reviewing this patch, and Cong Wang
> for his efforts on this problem.
>
> Fixes: 2860583fe840 ("ipv4: Kill rt->fi")
> Signed-off-by: Eric Dumazet <edumazet@google.com>
> Reported-by: Andrey Konovalov <andreyknvl@google.com>
Nice work, thanks!
Reviewed-by: Julian Anastasov <ja@ssi.bg>
> ---
> include/net/dst.h | 8 +++++++-
> include/net/ip_fib.h | 10 +++++-----
> net/core/dst.c | 23 ++++++++++++++---------
> net/ipv4/fib_semantics.c | 17 ++++++++++-------
> net/ipv4/route.c | 10 +++++++++-
> 5 files changed, 45 insertions(+), 23 deletions(-)
>
> diff --git a/include/net/dst.h b/include/net/dst.h
> index 049af33da3b6c95897d544670cea65c542317673..cfc0437841665d7ed46a714915c50d723c24901c 100644
> --- a/include/net/dst.h
> +++ b/include/net/dst.h
> @@ -107,10 +107,16 @@ struct dst_entry {
> };
> };
>
> +struct dst_metrics {
> + u32 metrics[RTAX_MAX];
> + atomic_t refcnt;
> +};
> +extern const struct dst_metrics dst_default_metrics;
> +
> u32 *dst_cow_metrics_generic(struct dst_entry *dst, unsigned long old);
> -extern const u32 dst_default_metrics[];
>
> #define DST_METRICS_READ_ONLY 0x1UL
> +#define DST_METRICS_REFCOUNTED 0x2UL
> #define DST_METRICS_FLAGS 0x3UL
> #define __DST_METRICS_PTR(Y) \
> ((u32 *)((Y) & ~DST_METRICS_FLAGS))
> diff --git a/include/net/ip_fib.h b/include/net/ip_fib.h
> index 6692c5758b332d468f1e0611ecc4f3e03ae03b2b..f7f6aa789c6174c41ca9739206d586c559c1f3a1 100644
> --- a/include/net/ip_fib.h
> +++ b/include/net/ip_fib.h
> @@ -114,11 +114,11 @@ struct fib_info {
> __be32 fib_prefsrc;
> u32 fib_tb_id;
> u32 fib_priority;
> - u32 *fib_metrics;
> -#define fib_mtu fib_metrics[RTAX_MTU-1]
> -#define fib_window fib_metrics[RTAX_WINDOW-1]
> -#define fib_rtt fib_metrics[RTAX_RTT-1]
> -#define fib_advmss fib_metrics[RTAX_ADVMSS-1]
> + struct dst_metrics *fib_metrics;
> +#define fib_mtu fib_metrics->metrics[RTAX_MTU-1]
> +#define fib_window fib_metrics->metrics[RTAX_WINDOW-1]
> +#define fib_rtt fib_metrics->metrics[RTAX_RTT-1]
> +#define fib_advmss fib_metrics->metrics[RTAX_ADVMSS-1]
> int fib_nhs;
> #ifdef CONFIG_IP_ROUTE_MULTIPATH
> int fib_weight;
> diff --git a/net/core/dst.c b/net/core/dst.c
> index 960e503b5a529a2c4f1866f49c150493ee98d7da..6192f11beec9077de964e2aeff4f78547f08b8da 100644
> --- a/net/core/dst.c
> +++ b/net/core/dst.c
> @@ -151,13 +151,13 @@ int dst_discard_out(struct net *net, struct sock *sk, struct sk_buff *skb)
> }
> EXPORT_SYMBOL(dst_discard_out);
>
> -const u32 dst_default_metrics[RTAX_MAX + 1] = {
> +const struct dst_metrics dst_default_metrics = {
> /* This initializer is needed to force linker to place this variable
> * into const section. Otherwise it might end into bss section.
> * We really want to avoid false sharing on this variable, and catch
> * any writes on it.
> */
> - [RTAX_MAX] = 0xdeadbeef,
> + .refcnt = ATOMIC_INIT(1),
> };
>
> void dst_init(struct dst_entry *dst, struct dst_ops *ops,
> @@ -169,7 +169,7 @@ void dst_init(struct dst_entry *dst, struct dst_ops *ops,
> if (dev)
> dev_hold(dev);
> dst->ops = ops;
> - dst_init_metrics(dst, dst_default_metrics, true);
> + dst_init_metrics(dst, dst_default_metrics.metrics, true);
> dst->expires = 0UL;
> dst->path = dst;
> dst->from = NULL;
> @@ -314,25 +314,30 @@ EXPORT_SYMBOL(dst_release);
>
> u32 *dst_cow_metrics_generic(struct dst_entry *dst, unsigned long old)
> {
> - u32 *p = kmalloc(sizeof(u32) * RTAX_MAX, GFP_ATOMIC);
> + struct dst_metrics *p = kmalloc(sizeof(*p), GFP_ATOMIC);
>
> if (p) {
> - u32 *old_p = __DST_METRICS_PTR(old);
> + struct dst_metrics *old_p = (struct dst_metrics *)__DST_METRICS_PTR(old);
> unsigned long prev, new;
>
> - memcpy(p, old_p, sizeof(u32) * RTAX_MAX);
> + atomic_set(&p->refcnt, 1);
> + memcpy(p->metrics, old_p->metrics, sizeof(p->metrics));
>
> new = (unsigned long) p;
> prev = cmpxchg(&dst->_metrics, old, new);
>
> if (prev != old) {
> kfree(p);
> - p = __DST_METRICS_PTR(prev);
> + p = (struct dst_metrics *)__DST_METRICS_PTR(prev);
> if (prev & DST_METRICS_READ_ONLY)
> p = NULL;
> + } else if (prev & DST_METRICS_REFCOUNTED) {
> + if (atomic_dec_and_test(&old_p->refcnt))
> + kfree(old_p);
> }
> }
> - return p;
> + BUILD_BUG_ON(offsetof(struct dst_metrics, metrics) != 0);
> + return (u32 *)p;
> }
> EXPORT_SYMBOL(dst_cow_metrics_generic);
>
> @@ -341,7 +346,7 @@ void __dst_destroy_metrics_generic(struct dst_entry *dst, unsigned long old)
> {
> unsigned long prev, new;
>
> - new = ((unsigned long) dst_default_metrics) | DST_METRICS_READ_ONLY;
> + new = ((unsigned long) &dst_default_metrics) | DST_METRICS_READ_ONLY;
> prev = cmpxchg(&dst->_metrics, old, new);
> if (prev == old)
> kfree(__DST_METRICS_PTR(old));
> diff --git a/net/ipv4/fib_semantics.c b/net/ipv4/fib_semantics.c
> index da449ddb8cc172bd9091c00057a69a095f98b56d..ad9ad4aab5da7c7d11c3b80edbdfcbdd3d7153fe 100644
> --- a/net/ipv4/fib_semantics.c
> +++ b/net/ipv4/fib_semantics.c
> @@ -203,6 +203,7 @@ static void rt_fibinfo_free_cpus(struct rtable __rcu * __percpu *rtp)
> static void free_fib_info_rcu(struct rcu_head *head)
> {
> struct fib_info *fi = container_of(head, struct fib_info, rcu);
> + struct dst_metrics *m;
>
> change_nexthops(fi) {
> if (nexthop_nh->nh_dev)
> @@ -213,8 +214,9 @@ static void free_fib_info_rcu(struct rcu_head *head)
> rt_fibinfo_free(&nexthop_nh->nh_rth_input);
> } endfor_nexthops(fi);
>
> - if (fi->fib_metrics != (u32 *) dst_default_metrics)
> - kfree(fi->fib_metrics);
> + m = fi->fib_metrics;
> + if (m != &dst_default_metrics && atomic_dec_and_test(&m->refcnt))
> + kfree(m);
> kfree(fi);
> }
>
> @@ -971,11 +973,11 @@ fib_convert_metrics(struct fib_info *fi, const struct fib_config *cfg)
> val = 255;
> if (type == RTAX_FEATURES && (val & ~RTAX_FEATURE_MASK))
> return -EINVAL;
> - fi->fib_metrics[type - 1] = val;
> + fi->fib_metrics->metrics[type - 1] = val;
> }
>
> if (ecn_ca)
> - fi->fib_metrics[RTAX_FEATURES - 1] |= DST_FEATURE_ECN_CA;
> + fi->fib_metrics->metrics[RTAX_FEATURES - 1] |= DST_FEATURE_ECN_CA;
>
> return 0;
> }
> @@ -1033,11 +1035,12 @@ struct fib_info *fib_create_info(struct fib_config *cfg)
> goto failure;
> fib_info_cnt++;
> if (cfg->fc_mx) {
> - fi->fib_metrics = kzalloc(sizeof(u32) * RTAX_MAX, GFP_KERNEL);
> + fi->fib_metrics = kzalloc(sizeof(*fi->fib_metrics), GFP_KERNEL);
> if (!fi->fib_metrics)
> goto failure;
> + atomic_set(&fi->fib_metrics->refcnt, 1);
> } else
> - fi->fib_metrics = (u32 *) dst_default_metrics;
> + fi->fib_metrics = (struct dst_metrics *)&dst_default_metrics;
>
> fi->fib_net = net;
> fi->fib_protocol = cfg->fc_protocol;
> @@ -1238,7 +1241,7 @@ int fib_dump_info(struct sk_buff *skb, u32 portid, u32 seq, int event,
> if (fi->fib_priority &&
> nla_put_u32(skb, RTA_PRIORITY, fi->fib_priority))
> goto nla_put_failure;
> - if (rtnetlink_put_metrics(skb, fi->fib_metrics) < 0)
> + if (rtnetlink_put_metrics(skb, fi->fib_metrics->metrics) < 0)
> goto nla_put_failure;
>
> if (fi->fib_prefsrc &&
> diff --git a/net/ipv4/route.c b/net/ipv4/route.c
> index 655d9eebe43e16a59102edcd3ea4bc177c6b341d..6883b3d4ba8f69de2cb924612d60f5671a219a84 100644
> --- a/net/ipv4/route.c
> +++ b/net/ipv4/route.c
> @@ -1385,8 +1385,12 @@ static void rt_add_uncached_list(struct rtable *rt)
>
> static void ipv4_dst_destroy(struct dst_entry *dst)
> {
> + struct dst_metrics *p = (struct dst_metrics *)DST_METRICS_PTR(dst);
> struct rtable *rt = (struct rtable *) dst;
>
> + if (p != &dst_default_metrics && atomic_dec_and_test(&p->refcnt))
> + kfree(p);
> +
> if (!list_empty(&rt->rt_uncached)) {
> struct uncached_list *ul = rt->rt_uncached_list;
>
> @@ -1438,7 +1442,11 @@ static void rt_set_nexthop(struct rtable *rt, __be32 daddr,
> rt->rt_gateway = nh->nh_gw;
> rt->rt_uses_gateway = 1;
> }
> - dst_init_metrics(&rt->dst, fi->fib_metrics, true);
> + dst_init_metrics(&rt->dst, fi->fib_metrics->metrics, true);
> + if (fi->fib_metrics != &dst_default_metrics) {
> + rt->dst._metrics |= DST_METRICS_REFCOUNTED;
> + atomic_inc(&fi->fib_metrics->refcnt);
> + }
> #ifdef CONFIG_IP_ROUTE_CLASSID
> rt->dst.tclassid = nh->nh_tclassid;
> #endif
Regards
^ permalink raw reply
* [PATCH v3 net-next 0/5] net: dsa: mv88e6xxx: Add basic SERDES support
From: Andrew Lunn @ 2017-05-25 23:03 UTC (permalink / raw)
To: David Miller; +Cc: Vivien Didelot, netdev, Andrew Lunn
Some of the Marvell switches are SERDES interface, which must be
powered up before packets can be passed. This is particularly true on
the 6390, where the SERDES defaults to down, probably to save power.
This series refactors the existing SERDES support for the 6352, and
adds 6390 support.
v2:
Split phy functions out into phy.[ch]
Don't add MV88E6XXX_FLAG_G1_ATU_FID back again
Move the serdes op up in mv88e6xxx_ops
Move some #defines into serdes.h
Add a mv88e6xxx_serdes_power()
Don't keep moving calls to this helper around in the code
v3:
Move more phy functions into phy.[ch]
Make mv88e6xxx_phy_page_get() and mv88e6xxx_phy_page_put static
Use the mv88e6xxx_serdes_power() helper everywhere
dev_err(...) when mv88e6xxx_serdes_power() fails
Add reviewed-by's
Andrew Lunn (5):
net: dsa: mv88e6xxx: Move phy functions into phy.[ch]
net: dsa: mv88e6xxx: Refactor mv88e6352 SERDES code into an op
net: dsa: mv88e6xxx: Remove SERDES flag
net: dsa: mv88e6xxx: mv88e6390X SERDES support
dsa: mv88e6xxx: Enable/Disable SERDES on port enable/disable
drivers/net/dsa/mv88e6xxx/Makefile | 2 +
drivers/net/dsa/mv88e6xxx/chip.c | 331 ++++++----------------------------
drivers/net/dsa/mv88e6xxx/mv88e6xxx.h | 31 +---
drivers/net/dsa/mv88e6xxx/phy.c | 243 +++++++++++++++++++++++++
drivers/net/dsa/mv88e6xxx/phy.h | 37 ++++
drivers/net/dsa/mv88e6xxx/serdes.c | 229 +++++++++++++++++++++++
drivers/net/dsa/mv88e6xxx/serdes.h | 48 +++++
7 files changed, 623 insertions(+), 298 deletions(-)
create mode 100644 drivers/net/dsa/mv88e6xxx/phy.c
create mode 100644 drivers/net/dsa/mv88e6xxx/phy.h
create mode 100644 drivers/net/dsa/mv88e6xxx/serdes.c
create mode 100644 drivers/net/dsa/mv88e6xxx/serdes.h
--
2.11.0
^ permalink raw reply
* [PATCH v3 net-next 1/5] net: dsa: mv88e6xxx: Move phy functions into phy.[ch]
From: Andrew Lunn @ 2017-05-25 23:03 UTC (permalink / raw)
To: David Miller; +Cc: Vivien Didelot, netdev, Andrew Lunn
In-Reply-To: <1495753404-29943-1-git-send-email-andrew@lunn.ch>
The upcoming SERDES support will need to make use of PHY functions. Move
them out into a file of there own. No code changes.
Signed-off-by: Andrew Lunn <andrew@lunn.ch>
---
drivers/net/dsa/mv88e6xxx/Makefile | 1 +
drivers/net/dsa/mv88e6xxx/chip.c | 233 +-------------------------------
drivers/net/dsa/mv88e6xxx/mv88e6xxx.h | 2 +-
drivers/net/dsa/mv88e6xxx/phy.c | 246 ++++++++++++++++++++++++++++++++++
drivers/net/dsa/mv88e6xxx/phy.h | 37 +++++
5 files changed, 287 insertions(+), 232 deletions(-)
create mode 100644 drivers/net/dsa/mv88e6xxx/phy.c
create mode 100644 drivers/net/dsa/mv88e6xxx/phy.h
diff --git a/drivers/net/dsa/mv88e6xxx/Makefile b/drivers/net/dsa/mv88e6xxx/Makefile
index 6edd869c8d6f..e4372eaf3bc5 100644
--- a/drivers/net/dsa/mv88e6xxx/Makefile
+++ b/drivers/net/dsa/mv88e6xxx/Makefile
@@ -4,4 +4,5 @@ mv88e6xxx-objs += global1.o
mv88e6xxx-objs += global1_atu.o
mv88e6xxx-objs += global1_vtu.o
mv88e6xxx-$(CONFIG_NET_DSA_MV88E6XXX_GLOBAL2) += global2.o
+mv88e6xxx-objs += phy.o
mv88e6xxx-objs += port.o
diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c
index 41de250dbcc3..724f3b09e077 100644
--- a/drivers/net/dsa/mv88e6xxx/chip.c
+++ b/drivers/net/dsa/mv88e6xxx/chip.c
@@ -36,6 +36,7 @@
#include "mv88e6xxx.h"
#include "global1.h"
#include "global2.h"
+#include "phy.h"
#include "port.h"
static void assert_reg_lock(struct mv88e6xxx_chip *chip)
@@ -221,21 +222,7 @@ int mv88e6xxx_write(struct mv88e6xxx_chip *chip, int addr, int reg, u16 val)
return 0;
}
-static int mv88e6165_phy_read(struct mv88e6xxx_chip *chip,
- struct mii_bus *bus,
- int addr, int reg, u16 *val)
-{
- return mv88e6xxx_read(chip, addr, reg, val);
-}
-
-static int mv88e6165_phy_write(struct mv88e6xxx_chip *chip,
- struct mii_bus *bus,
- int addr, int reg, u16 val)
-{
- return mv88e6xxx_write(chip, addr, reg, val);
-}
-
-static struct mii_bus *mv88e6xxx_default_mdio_bus(struct mv88e6xxx_chip *chip)
+struct mii_bus *mv88e6xxx_default_mdio_bus(struct mv88e6xxx_chip *chip)
{
struct mv88e6xxx_mdio_bus *mdio_bus;
@@ -247,94 +234,6 @@ static struct mii_bus *mv88e6xxx_default_mdio_bus(struct mv88e6xxx_chip *chip)
return mdio_bus->bus;
}
-static int mv88e6xxx_phy_read(struct mv88e6xxx_chip *chip, int phy,
- int reg, u16 *val)
-{
- int addr = phy; /* PHY devices addresses start at 0x0 */
- struct mii_bus *bus;
-
- bus = mv88e6xxx_default_mdio_bus(chip);
- if (!bus)
- return -EOPNOTSUPP;
-
- if (!chip->info->ops->phy_read)
- return -EOPNOTSUPP;
-
- return chip->info->ops->phy_read(chip, bus, addr, reg, val);
-}
-
-static int mv88e6xxx_phy_write(struct mv88e6xxx_chip *chip, int phy,
- int reg, u16 val)
-{
- int addr = phy; /* PHY devices addresses start at 0x0 */
- struct mii_bus *bus;
-
- bus = mv88e6xxx_default_mdio_bus(chip);
- if (!bus)
- return -EOPNOTSUPP;
-
- if (!chip->info->ops->phy_write)
- return -EOPNOTSUPP;
-
- return chip->info->ops->phy_write(chip, bus, addr, reg, val);
-}
-
-static int mv88e6xxx_phy_page_get(struct mv88e6xxx_chip *chip, int phy, u8 page)
-{
- if (!mv88e6xxx_has(chip, MV88E6XXX_FLAG_PHY_PAGE))
- return -EOPNOTSUPP;
-
- return mv88e6xxx_phy_write(chip, phy, PHY_PAGE, page);
-}
-
-static void mv88e6xxx_phy_page_put(struct mv88e6xxx_chip *chip, int phy)
-{
- int err;
-
- /* Restore PHY page Copper 0x0 for access via the registered MDIO bus */
- err = mv88e6xxx_phy_write(chip, phy, PHY_PAGE, PHY_PAGE_COPPER);
- if (unlikely(err)) {
- dev_err(chip->dev, "failed to restore PHY %d page Copper (%d)\n",
- phy, err);
- }
-}
-
-static int mv88e6xxx_phy_page_read(struct mv88e6xxx_chip *chip, int phy,
- u8 page, int reg, u16 *val)
-{
- int err;
-
- /* There is no paging for registers 22 */
- if (reg == PHY_PAGE)
- return -EINVAL;
-
- err = mv88e6xxx_phy_page_get(chip, phy, page);
- if (!err) {
- err = mv88e6xxx_phy_read(chip, phy, reg, val);
- mv88e6xxx_phy_page_put(chip, phy);
- }
-
- return err;
-}
-
-static int mv88e6xxx_phy_page_write(struct mv88e6xxx_chip *chip, int phy,
- u8 page, int reg, u16 val)
-{
- int err;
-
- /* There is no paging for registers 22 */
- if (reg == PHY_PAGE)
- return -EINVAL;
-
- err = mv88e6xxx_phy_page_get(chip, phy, page);
- if (!err) {
- err = mv88e6xxx_phy_write(chip, phy, PHY_PAGE, page);
- mv88e6xxx_phy_page_put(chip, phy);
- }
-
- return err;
-}
-
static int mv88e6xxx_serdes_read(struct mv88e6xxx_chip *chip, int reg, u16 *val)
{
return mv88e6xxx_phy_page_read(chip, ADDR_SERDES, SERDES_PAGE_FIBER,
@@ -560,122 +459,6 @@ int mv88e6xxx_update(struct mv88e6xxx_chip *chip, int addr, int reg, u16 update)
return mv88e6xxx_write(chip, addr, reg, val);
}
-static int mv88e6xxx_ppu_disable(struct mv88e6xxx_chip *chip)
-{
- if (!chip->info->ops->ppu_disable)
- return 0;
-
- return chip->info->ops->ppu_disable(chip);
-}
-
-static int mv88e6xxx_ppu_enable(struct mv88e6xxx_chip *chip)
-{
- if (!chip->info->ops->ppu_enable)
- return 0;
-
- return chip->info->ops->ppu_enable(chip);
-}
-
-static void mv88e6xxx_ppu_reenable_work(struct work_struct *ugly)
-{
- struct mv88e6xxx_chip *chip;
-
- chip = container_of(ugly, struct mv88e6xxx_chip, ppu_work);
-
- mutex_lock(&chip->reg_lock);
-
- if (mutex_trylock(&chip->ppu_mutex)) {
- if (mv88e6xxx_ppu_enable(chip) == 0)
- chip->ppu_disabled = 0;
- mutex_unlock(&chip->ppu_mutex);
- }
-
- mutex_unlock(&chip->reg_lock);
-}
-
-static void mv88e6xxx_ppu_reenable_timer(unsigned long _ps)
-{
- struct mv88e6xxx_chip *chip = (void *)_ps;
-
- schedule_work(&chip->ppu_work);
-}
-
-static int mv88e6xxx_ppu_access_get(struct mv88e6xxx_chip *chip)
-{
- int ret;
-
- mutex_lock(&chip->ppu_mutex);
-
- /* If the PHY polling unit is enabled, disable it so that
- * we can access the PHY registers. If it was already
- * disabled, cancel the timer that is going to re-enable
- * it.
- */
- if (!chip->ppu_disabled) {
- ret = mv88e6xxx_ppu_disable(chip);
- if (ret < 0) {
- mutex_unlock(&chip->ppu_mutex);
- return ret;
- }
- chip->ppu_disabled = 1;
- } else {
- del_timer(&chip->ppu_timer);
- ret = 0;
- }
-
- return ret;
-}
-
-static void mv88e6xxx_ppu_access_put(struct mv88e6xxx_chip *chip)
-{
- /* Schedule a timer to re-enable the PHY polling unit. */
- mod_timer(&chip->ppu_timer, jiffies + msecs_to_jiffies(10));
- mutex_unlock(&chip->ppu_mutex);
-}
-
-static void mv88e6xxx_ppu_state_init(struct mv88e6xxx_chip *chip)
-{
- mutex_init(&chip->ppu_mutex);
- INIT_WORK(&chip->ppu_work, mv88e6xxx_ppu_reenable_work);
- setup_timer(&chip->ppu_timer, mv88e6xxx_ppu_reenable_timer,
- (unsigned long)chip);
-}
-
-static void mv88e6xxx_ppu_state_destroy(struct mv88e6xxx_chip *chip)
-{
- del_timer_sync(&chip->ppu_timer);
-}
-
-static int mv88e6xxx_phy_ppu_read(struct mv88e6xxx_chip *chip,
- struct mii_bus *bus,
- int addr, int reg, u16 *val)
-{
- int err;
-
- err = mv88e6xxx_ppu_access_get(chip);
- if (!err) {
- err = mv88e6xxx_read(chip, addr, reg, val);
- mv88e6xxx_ppu_access_put(chip);
- }
-
- return err;
-}
-
-static int mv88e6xxx_phy_ppu_write(struct mv88e6xxx_chip *chip,
- struct mii_bus *bus,
- int addr, int reg, u16 val)
-{
- int err;
-
- err = mv88e6xxx_ppu_access_get(chip);
- if (!err) {
- err = mv88e6xxx_write(chip, addr, reg, val);
- mv88e6xxx_ppu_access_put(chip);
- }
-
- return err;
-}
-
static int mv88e6xxx_port_setup_mac(struct mv88e6xxx_chip *chip, int port,
int link, int speed, int duplex,
phy_interface_t mode)
@@ -3914,18 +3697,6 @@ static struct mv88e6xxx_chip *mv88e6xxx_alloc_chip(struct device *dev)
return chip;
}
-static void mv88e6xxx_phy_init(struct mv88e6xxx_chip *chip)
-{
- if (chip->info->ops->ppu_enable && chip->info->ops->ppu_disable)
- mv88e6xxx_ppu_state_init(chip);
-}
-
-static void mv88e6xxx_phy_destroy(struct mv88e6xxx_chip *chip)
-{
- if (chip->info->ops->ppu_enable && chip->info->ops->ppu_disable)
- mv88e6xxx_ppu_state_destroy(chip);
-}
-
static int mv88e6xxx_smi_init(struct mv88e6xxx_chip *chip,
struct mii_bus *bus, int sw_addr)
{
diff --git a/drivers/net/dsa/mv88e6xxx/mv88e6xxx.h b/drivers/net/dsa/mv88e6xxx/mv88e6xxx.h
index 77236cd72df2..45b387c780a8 100644
--- a/drivers/net/dsa/mv88e6xxx/mv88e6xxx.h
+++ b/drivers/net/dsa/mv88e6xxx/mv88e6xxx.h
@@ -942,5 +942,5 @@ int mv88e6xxx_write(struct mv88e6xxx_chip *chip, int addr, int reg, u16 val);
int mv88e6xxx_update(struct mv88e6xxx_chip *chip, int addr, int reg,
u16 update);
int mv88e6xxx_wait(struct mv88e6xxx_chip *chip, int addr, int reg, u16 mask);
-
+struct mii_bus *mv88e6xxx_default_mdio_bus(struct mv88e6xxx_chip *chip);
#endif
diff --git a/drivers/net/dsa/mv88e6xxx/phy.c b/drivers/net/dsa/mv88e6xxx/phy.c
new file mode 100644
index 000000000000..0e6c72b93c8f
--- /dev/null
+++ b/drivers/net/dsa/mv88e6xxx/phy.c
@@ -0,0 +1,246 @@
+/*
+ * Marvell 88e6xxx Ethernet switch PHY and PPU support
+ *
+ * Copyright (c) 2008 Marvell Semiconductor
+ *
+ * Copyright (c) 2017 Andrew Lunn <andrew@lunn.ch>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/mdio.h>
+#include <linux/module.h>
+#include <net/dsa.h>
+
+#include "mv88e6xxx.h"
+#include "phy.h"
+
+int mv88e6165_phy_read(struct mv88e6xxx_chip *chip, struct mii_bus *bus,
+ int addr, int reg, u16 *val)
+{
+ return mv88e6xxx_read(chip, addr, reg, val);
+}
+
+int mv88e6165_phy_write(struct mv88e6xxx_chip *chip, struct mii_bus *bus,
+ int addr, int reg, u16 val)
+{
+ return mv88e6xxx_write(chip, addr, reg, val);
+}
+
+int mv88e6xxx_phy_read(struct mv88e6xxx_chip *chip, int phy, int reg, u16 *val)
+{
+ int addr = phy; /* PHY devices addresses start at 0x0 */
+ struct mii_bus *bus;
+
+ bus = mv88e6xxx_default_mdio_bus(chip);
+ if (!bus)
+ return -EOPNOTSUPP;
+
+ if (!chip->info->ops->phy_read)
+ return -EOPNOTSUPP;
+
+ return chip->info->ops->phy_read(chip, bus, addr, reg, val);
+}
+
+int mv88e6xxx_phy_write(struct mv88e6xxx_chip *chip, int phy, int reg, u16 val)
+{
+ int addr = phy; /* PHY devices addresses start at 0x0 */
+ struct mii_bus *bus;
+
+ bus = mv88e6xxx_default_mdio_bus(chip);
+ if (!bus)
+ return -EOPNOTSUPP;
+
+ if (!chip->info->ops->phy_write)
+ return -EOPNOTSUPP;
+
+ return chip->info->ops->phy_write(chip, bus, addr, reg, val);
+}
+
+static int mv88e6xxx_phy_page_get(struct mv88e6xxx_chip *chip, int phy, u8 page)
+{
+ if (!mv88e6xxx_has(chip, MV88E6XXX_FLAG_PHY_PAGE))
+ return -EOPNOTSUPP;
+
+ return mv88e6xxx_phy_write(chip, phy, PHY_PAGE, page);
+}
+
+static void mv88e6xxx_phy_page_put(struct mv88e6xxx_chip *chip, int phy)
+{
+ int err;
+
+ /* Restore PHY page Copper 0x0 for access via the registered
+ * MDIO bus
+ */
+ err = mv88e6xxx_phy_write(chip, phy, PHY_PAGE, PHY_PAGE_COPPER);
+ if (unlikely(err)) {
+ dev_err(chip->dev,
+ "failed to restore PHY %d page Copper (%d)\n",
+ phy, err);
+ }
+}
+
+int mv88e6xxx_phy_page_read(struct mv88e6xxx_chip *chip, int phy,
+ u8 page, int reg, u16 *val)
+{
+ int err;
+
+ /* There is no paging for registers 22 */
+ if (reg == PHY_PAGE)
+ return -EINVAL;
+
+ err = mv88e6xxx_phy_page_get(chip, phy, page);
+ if (!err) {
+ err = mv88e6xxx_phy_read(chip, phy, reg, val);
+ mv88e6xxx_phy_page_put(chip, phy);
+ }
+
+ return err;
+}
+
+int mv88e6xxx_phy_page_write(struct mv88e6xxx_chip *chip, int phy,
+ u8 page, int reg, u16 val)
+{
+ int err;
+
+ /* There is no paging for registers 22 */
+ if (reg == PHY_PAGE)
+ return -EINVAL;
+
+ err = mv88e6xxx_phy_page_get(chip, phy, page);
+ if (!err) {
+ err = mv88e6xxx_phy_write(chip, phy, PHY_PAGE, page);
+ mv88e6xxx_phy_page_put(chip, phy);
+ }
+
+ return err;
+}
+
+static int mv88e6xxx_ppu_disable(struct mv88e6xxx_chip *chip)
+{
+ if (!chip->info->ops->ppu_disable)
+ return 0;
+
+ return chip->info->ops->ppu_disable(chip);
+}
+
+int mv88e6xxx_ppu_enable(struct mv88e6xxx_chip *chip)
+{
+ if (!chip->info->ops->ppu_enable)
+ return 0;
+
+ return chip->info->ops->ppu_enable(chip);
+}
+
+static void mv88e6xxx_ppu_reenable_work(struct work_struct *ugly)
+{
+ struct mv88e6xxx_chip *chip;
+
+ chip = container_of(ugly, struct mv88e6xxx_chip, ppu_work);
+
+ mutex_lock(&chip->reg_lock);
+
+ if (mutex_trylock(&chip->ppu_mutex)) {
+ if (mv88e6xxx_ppu_enable(chip) == 0)
+ chip->ppu_disabled = 0;
+ mutex_unlock(&chip->ppu_mutex);
+ }
+
+ mutex_unlock(&chip->reg_lock);
+}
+
+static void mv88e6xxx_ppu_reenable_timer(unsigned long _ps)
+{
+ struct mv88e6xxx_chip *chip = (void *)_ps;
+
+ schedule_work(&chip->ppu_work);
+}
+
+static int mv88e6xxx_ppu_access_get(struct mv88e6xxx_chip *chip)
+{
+ int ret;
+
+ mutex_lock(&chip->ppu_mutex);
+
+ /* If the PHY polling unit is enabled, disable it so that
+ * we can access the PHY registers. If it was already
+ * disabled, cancel the timer that is going to re-enable
+ * it.
+ */
+ if (!chip->ppu_disabled) {
+ ret = mv88e6xxx_ppu_disable(chip);
+ if (ret < 0) {
+ mutex_unlock(&chip->ppu_mutex);
+ return ret;
+ }
+ chip->ppu_disabled = 1;
+ } else {
+ del_timer(&chip->ppu_timer);
+ ret = 0;
+ }
+
+ return ret;
+}
+
+static void mv88e6xxx_ppu_access_put(struct mv88e6xxx_chip *chip)
+{
+ /* Schedule a timer to re-enable the PHY polling unit. */
+ mod_timer(&chip->ppu_timer, jiffies + msecs_to_jiffies(10));
+ mutex_unlock(&chip->ppu_mutex);
+}
+
+static void mv88e6xxx_ppu_state_init(struct mv88e6xxx_chip *chip)
+{
+ mutex_init(&chip->ppu_mutex);
+ INIT_WORK(&chip->ppu_work, mv88e6xxx_ppu_reenable_work);
+ setup_timer(&chip->ppu_timer, mv88e6xxx_ppu_reenable_timer,
+ (unsigned long)chip);
+}
+
+static void mv88e6xxx_ppu_state_destroy(struct mv88e6xxx_chip *chip)
+{
+ del_timer_sync(&chip->ppu_timer);
+}
+
+int mv88e6xxx_phy_ppu_read(struct mv88e6xxx_chip *chip, struct mii_bus *bus,
+ int addr, int reg, u16 *val)
+{
+ int err;
+
+ err = mv88e6xxx_ppu_access_get(chip);
+ if (!err) {
+ err = mv88e6xxx_read(chip, addr, reg, val);
+ mv88e6xxx_ppu_access_put(chip);
+ }
+
+ return err;
+}
+
+int mv88e6xxx_phy_ppu_write(struct mv88e6xxx_chip *chip, struct mii_bus *bus,
+ int addr, int reg, u16 val)
+{
+ int err;
+
+ err = mv88e6xxx_ppu_access_get(chip);
+ if (!err) {
+ err = mv88e6xxx_write(chip, addr, reg, val);
+ mv88e6xxx_ppu_access_put(chip);
+ }
+
+ return err;
+}
+
+void mv88e6xxx_phy_init(struct mv88e6xxx_chip *chip)
+{
+ if (chip->info->ops->ppu_enable && chip->info->ops->ppu_disable)
+ mv88e6xxx_ppu_state_init(chip);
+}
+
+void mv88e6xxx_phy_destroy(struct mv88e6xxx_chip *chip)
+{
+ if (chip->info->ops->ppu_enable && chip->info->ops->ppu_disable)
+ mv88e6xxx_ppu_state_destroy(chip);
+}
diff --git a/drivers/net/dsa/mv88e6xxx/phy.h b/drivers/net/dsa/mv88e6xxx/phy.h
new file mode 100644
index 000000000000..0961d781b726
--- /dev/null
+++ b/drivers/net/dsa/mv88e6xxx/phy.h
@@ -0,0 +1,37 @@
+/*
+ * Marvell 88E6xxx PHY access
+ *
+ * Copyright (c) 2008 Marvell Semiconductor
+ *
+ * Copyright (c) 2017 Andrew Lunn <andrew@lunn.ch>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#ifndef _MV88E6XXX_PHY_H
+#define _MV88E6XXX_PHY_H
+
+int mv88e6165_phy_read(struct mv88e6xxx_chip *chip, struct mii_bus *bus,
+ int addr, int reg, u16 *val);
+int mv88e6165_phy_write(struct mv88e6xxx_chip *chip, struct mii_bus *bus,
+ int addr, int reg, u16 val);
+int mv88e6xxx_phy_read(struct mv88e6xxx_chip *chip, int phy,
+ int reg, u16 *val);
+int mv88e6xxx_phy_write(struct mv88e6xxx_chip *chip, int phy,
+ int reg, u16 val);
+int mv88e6xxx_phy_page_read(struct mv88e6xxx_chip *chip, int phy,
+ u8 page, int reg, u16 *val);
+int mv88e6xxx_phy_page_write(struct mv88e6xxx_chip *chip, int phy,
+ u8 page, int reg, u16 val);
+int mv88e6xxx_phy_ppu_read(struct mv88e6xxx_chip *chip, struct mii_bus *bus,
+ int addr, int reg, u16 *val);
+int mv88e6xxx_phy_ppu_write(struct mv88e6xxx_chip *chip, struct mii_bus *bus,
+ int addr, int reg, u16 val);
+int mv88e6xxx_ppu_enable(struct mv88e6xxx_chip *chip);
+void mv88e6xxx_phy_init(struct mv88e6xxx_chip *chip);
+void mv88e6xxx_phy_destroy(struct mv88e6xxx_chip *chip);
+
+#endif /*_MV88E6XXX_PHY_H */
--
2.11.0
^ permalink raw reply related
* [PATCH v3 net-next 2/5] net: dsa: mv88e6xxx: Refactor mv88e6352 SERDES code into an op
From: Andrew Lunn @ 2017-05-25 23:03 UTC (permalink / raw)
To: David Miller; +Cc: Vivien Didelot, netdev, Andrew Lunn
In-Reply-To: <1495753404-29943-1-git-send-email-andrew@lunn.ch>
The mv88e6390 family has a different SERDES implementation. Refactor
the mv88e6352 code into an ops function, so we can later add the
mv88e6390 code.
Signed-off-by: Andrew Lunn <andrew@lunn.ch>
Reviewed-by: Vivien Didelot <vivien.didelot@savoirfairelinux.com>
---
drivers/net/dsa/mv88e6xxx/Makefile | 1 +
drivers/net/dsa/mv88e6xxx/chip.c | 64 +++++++++---------------------
drivers/net/dsa/mv88e6xxx/mv88e6xxx.h | 6 +--
drivers/net/dsa/mv88e6xxx/serdes.c | 75 +++++++++++++++++++++++++++++++++++
drivers/net/dsa/mv88e6xxx/serdes.h | 24 +++++++++++
5 files changed, 122 insertions(+), 48 deletions(-)
create mode 100644 drivers/net/dsa/mv88e6xxx/serdes.c
create mode 100644 drivers/net/dsa/mv88e6xxx/serdes.h
diff --git a/drivers/net/dsa/mv88e6xxx/Makefile b/drivers/net/dsa/mv88e6xxx/Makefile
index e4372eaf3bc5..5cd5551461e3 100644
--- a/drivers/net/dsa/mv88e6xxx/Makefile
+++ b/drivers/net/dsa/mv88e6xxx/Makefile
@@ -6,3 +6,4 @@ mv88e6xxx-objs += global1_vtu.o
mv88e6xxx-$(CONFIG_NET_DSA_MV88E6XXX_GLOBAL2) += global2.o
mv88e6xxx-objs += phy.o
mv88e6xxx-objs += port.o
+mv88e6xxx-objs += serdes.o
diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c
index 724f3b09e077..bc7b345d91d3 100644
--- a/drivers/net/dsa/mv88e6xxx/chip.c
+++ b/drivers/net/dsa/mv88e6xxx/chip.c
@@ -38,6 +38,7 @@
#include "global2.h"
#include "phy.h"
#include "port.h"
+#include "serdes.h"
static void assert_reg_lock(struct mv88e6xxx_chip *chip)
{
@@ -234,18 +235,6 @@ struct mii_bus *mv88e6xxx_default_mdio_bus(struct mv88e6xxx_chip *chip)
return mdio_bus->bus;
}
-static int mv88e6xxx_serdes_read(struct mv88e6xxx_chip *chip, int reg, u16 *val)
-{
- return mv88e6xxx_phy_page_read(chip, ADDR_SERDES, SERDES_PAGE_FIBER,
- reg, val);
-}
-
-static int mv88e6xxx_serdes_write(struct mv88e6xxx_chip *chip, int reg, u16 val)
-{
- return mv88e6xxx_phy_page_write(chip, ADDR_SERDES, SERDES_PAGE_FIBER,
- reg, val);
-}
-
static void mv88e6xxx_g1_irq_mask(struct irq_data *d)
{
struct mv88e6xxx_chip *chip = irq_data_get_irq_chip_data(d);
@@ -1733,24 +1722,6 @@ static int mv88e6xxx_switch_reset(struct mv88e6xxx_chip *chip)
return mv88e6xxx_software_reset(chip);
}
-static int mv88e6xxx_serdes_power_on(struct mv88e6xxx_chip *chip)
-{
- u16 val;
- int err;
-
- /* Clear Power Down bit */
- err = mv88e6xxx_serdes_read(chip, MII_BMCR, &val);
- if (err)
- return err;
-
- if (val & BMCR_PDOWN) {
- val &= ~BMCR_PDOWN;
- err = mv88e6xxx_serdes_write(chip, MII_BMCR, val);
- }
-
- return err;
-}
-
static int mv88e6xxx_set_port_mode(struct mv88e6xxx_chip *chip, int port,
enum mv88e6xxx_frame_mode frame, u16 egress,
u16 etype)
@@ -1832,6 +1803,15 @@ static int mv88e6xxx_setup_egress_floods(struct mv88e6xxx_chip *chip, int port)
return 0;
}
+static int mv88e6xxx_serdes_power(struct mv88e6xxx_chip *chip, int port,
+ bool on)
+{
+ if (chip->info->ops->serdes_power)
+ return chip->info->ops->serdes_power(chip, port, on);
+
+ return 0;
+}
+
static int mv88e6xxx_setup_port(struct mv88e6xxx_chip *chip, int port)
{
struct dsa_switch *ds = chip->ds;
@@ -1882,22 +1862,12 @@ static int mv88e6xxx_setup_port(struct mv88e6xxx_chip *chip, int port)
if (err)
return err;
- /* If this port is connected to a SerDes, make sure the SerDes is not
- * powered down.
+ /* If this port is connected to a SerDes, make sure the SerDes is
+ * powered up.
*/
- if (mv88e6xxx_has(chip, MV88E6XXX_FLAGS_SERDES)) {
- err = mv88e6xxx_port_read(chip, port, PORT_STATUS, ®);
- if (err)
- return err;
- reg &= PORT_STATUS_CMODE_MASK;
- if ((reg == PORT_STATUS_CMODE_100BASE_X) ||
- (reg == PORT_STATUS_CMODE_1000BASE_X) ||
- (reg == PORT_STATUS_CMODE_SGMII)) {
- err = mv88e6xxx_serdes_power_on(chip);
- if (err < 0)
- return err;
- }
- }
+ err = mv88e6xxx_serdes_power(chip, port, true);
+ if (err)
+ return err;
/* Port Control 2: don't force a good FCS, set the maximum frame size to
* 10240 bytes, disable 802.1q tags checking, don't discard tagged or
@@ -2662,6 +2632,7 @@ static const struct mv88e6xxx_ops mv88e6172_ops = {
.reset = mv88e6352_g1_reset,
.vtu_getnext = mv88e6352_g1_vtu_getnext,
.vtu_loadpurge = mv88e6352_g1_vtu_loadpurge,
+ .serdes_power = mv88e6352_serdes_power,
};
static const struct mv88e6xxx_ops mv88e6175_ops = {
@@ -2726,6 +2697,7 @@ static const struct mv88e6xxx_ops mv88e6176_ops = {
.reset = mv88e6352_g1_reset,
.vtu_getnext = mv88e6352_g1_vtu_getnext,
.vtu_loadpurge = mv88e6352_g1_vtu_loadpurge,
+ .serdes_power = mv88e6352_serdes_power,
};
static const struct mv88e6xxx_ops mv88e6185_ops = {
@@ -2882,6 +2854,7 @@ static const struct mv88e6xxx_ops mv88e6240_ops = {
.reset = mv88e6352_g1_reset,
.vtu_getnext = mv88e6352_g1_vtu_getnext,
.vtu_loadpurge = mv88e6352_g1_vtu_loadpurge,
+ .serdes_power = mv88e6352_serdes_power,
};
static const struct mv88e6xxx_ops mv88e6290_ops = {
@@ -3104,6 +3077,7 @@ static const struct mv88e6xxx_ops mv88e6352_ops = {
.reset = mv88e6352_g1_reset,
.vtu_getnext = mv88e6352_g1_vtu_getnext,
.vtu_loadpurge = mv88e6352_g1_vtu_loadpurge,
+ .serdes_power = mv88e6352_serdes_power,
};
static const struct mv88e6xxx_ops mv88e6390_ops = {
diff --git a/drivers/net/dsa/mv88e6xxx/mv88e6xxx.h b/drivers/net/dsa/mv88e6xxx/mv88e6xxx.h
index 45b387c780a8..fb996491b111 100644
--- a/drivers/net/dsa/mv88e6xxx/mv88e6xxx.h
+++ b/drivers/net/dsa/mv88e6xxx/mv88e6xxx.h
@@ -37,9 +37,6 @@
#define PHY_PAGE 0x16
#define PHY_PAGE_COPPER 0x00
-#define ADDR_SERDES 0x0f
-#define SERDES_PAGE_FIBER 0x01
-
#define PORT_STATUS 0x00
#define PORT_STATUS_PAUSE_EN BIT(15)
#define PORT_STATUS_MY_PAUSE BIT(14)
@@ -884,6 +881,9 @@ struct mv88e6xxx_ops {
/* Can be either in g1 or g2, so don't use a prefix */
int (*mgmt_rsvd2cpu)(struct mv88e6xxx_chip *chip);
+ /* Power on/off a SERDES interface */
+ int (*serdes_power)(struct mv88e6xxx_chip *chip, int port, bool on);
+
/* VLAN Translation Unit operations */
int (*vtu_getnext)(struct mv88e6xxx_chip *chip,
struct mv88e6xxx_vtu_entry *entry);
diff --git a/drivers/net/dsa/mv88e6xxx/serdes.c b/drivers/net/dsa/mv88e6xxx/serdes.c
new file mode 100644
index 000000000000..235f5f0c30ae
--- /dev/null
+++ b/drivers/net/dsa/mv88e6xxx/serdes.c
@@ -0,0 +1,75 @@
+/*
+ * Marvell 88E6xxx SERDES manipulation, via SMI bus
+ *
+ * Copyright (c) 2008 Marvell Semiconductor
+ *
+ * Copyright (c) 2017 Andrew Lunn <andrew@lunn.ch>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/mii.h>
+
+#include "mv88e6xxx.h"
+#include "phy.h"
+#include "port.h"
+#include "serdes.h"
+
+static int mv88e6352_serdes_read(struct mv88e6xxx_chip *chip, int reg,
+ u16 *val)
+{
+ return mv88e6xxx_phy_page_read(chip, MV88E6352_ADDR_SERDES,
+ MV88E6352_SERDES_PAGE_FIBER,
+ reg, val);
+}
+
+static int mv88e6352_serdes_write(struct mv88e6xxx_chip *chip, int reg,
+ u16 val)
+{
+ return mv88e6xxx_phy_page_write(chip, MV88E6352_ADDR_SERDES,
+ MV88E6352_SERDES_PAGE_FIBER,
+ reg, val);
+}
+
+static int mv88e6352_serdes_power_set(struct mv88e6xxx_chip *chip, bool on)
+{
+ u16 val, new_val;
+ int err;
+
+ err = mv88e6352_serdes_read(chip, MII_BMCR, &val);
+ if (err)
+ return err;
+
+ if (on)
+ new_val = val & ~BMCR_PDOWN;
+ else
+ new_val = val | BMCR_PDOWN;
+
+ if (val != new_val)
+ err = mv88e6352_serdes_write(chip, MII_BMCR, new_val);
+
+ return err;
+}
+
+int mv88e6352_serdes_power(struct mv88e6xxx_chip *chip, int port, bool on)
+{
+ int err;
+ u8 cmode;
+
+ err = mv88e6xxx_port_get_cmode(chip, port, &cmode);
+ if (err)
+ return err;
+
+ if ((cmode == PORT_STATUS_CMODE_100BASE_X) ||
+ (cmode == PORT_STATUS_CMODE_1000BASE_X) ||
+ (cmode == PORT_STATUS_CMODE_SGMII)) {
+ err = mv88e6352_serdes_power_set(chip, on);
+ if (err < 0)
+ return err;
+ }
+
+ return 0;
+}
diff --git a/drivers/net/dsa/mv88e6xxx/serdes.h b/drivers/net/dsa/mv88e6xxx/serdes.h
new file mode 100644
index 000000000000..a690be09ac52
--- /dev/null
+++ b/drivers/net/dsa/mv88e6xxx/serdes.h
@@ -0,0 +1,24 @@
+/*
+ * Marvell 88E6xxx SERDES manipulation, via SMI bus
+ *
+ * Copyright (c) 2008 Marvell Semiconductor
+ *
+ * Copyright (c) 2016 Andrew Lunn <andrew@lunn.ch>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#ifndef _MV88E6XXX_SERDES_H
+#define _MV88E6XXX_SERDES_H
+
+#include "mv88e6xxx.h"
+
+#define MV88E6352_ADDR_SERDES 0x0f
+#define MV88E6352_SERDES_PAGE_FIBER 0x01
+
+int mv88e6352_serdes_power(struct mv88e6xxx_chip *chip, int port, bool on);
+
+#endif
--
2.11.0
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox