Skip to content

Commit 3e78815

Browse files
committed
Merge branch 'phy-marvell-support-downshift-as-PHY-tunable'
Heiner Kallweit says: ==================== net: phy: marvell: support downshift as PHY tunable So far downshift is implemented for one small use case only and can't be controlled from userspace. So let's implement this feature properly as a PHY tunable so that it can be controlled via ethtool. ==================== Signed-off-by: David S. Miller <[email protected]>
2 parents a8fad54 + e2d861c commit 3e78815

File tree

1 file changed

+122
-54
lines changed

1 file changed

+122
-54
lines changed

drivers/net/phy/marvell.c

Lines changed: 122 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -53,12 +53,15 @@
5353

5454
#define MII_M1011_PHY_SCR 0x10
5555
#define MII_M1011_PHY_SCR_DOWNSHIFT_EN BIT(11)
56-
#define MII_M1011_PHY_SCR_DOWNSHIFT_SHIFT 12
57-
#define MII_M1011_PHY_SRC_DOWNSHIFT_MASK 0x7800
56+
#define MII_M1011_PHY_SRC_DOWNSHIFT_MASK GENMASK(14, 12)
57+
#define MII_M1011_PHY_SCR_DOWNSHIFT_MAX 8
5858
#define MII_M1011_PHY_SCR_MDI (0x0 << 5)
5959
#define MII_M1011_PHY_SCR_MDI_X (0x1 << 5)
6060
#define MII_M1011_PHY_SCR_AUTO_CROSS (0x3 << 5)
6161

62+
#define MII_M1011_PHY_SSR 0x11
63+
#define MII_M1011_PHY_SSR_DOWNSHIFT BIT(5)
64+
6265
#define MII_M1111_PHY_LED_CONTROL 0x18
6366
#define MII_M1111_PHY_LED_DIRECT 0x4100
6467
#define MII_M1111_PHY_LED_COMBINE 0x411c
@@ -273,23 +276,6 @@ static int marvell_set_polarity(struct phy_device *phydev, int polarity)
273276
return val != reg;
274277
}
275278

276-
static int marvell_set_downshift(struct phy_device *phydev, bool enable,
277-
u8 retries)
278-
{
279-
int reg;
280-
281-
reg = phy_read(phydev, MII_M1011_PHY_SCR);
282-
if (reg < 0)
283-
return reg;
284-
285-
reg &= MII_M1011_PHY_SRC_DOWNSHIFT_MASK;
286-
reg |= ((retries - 1) << MII_M1011_PHY_SCR_DOWNSHIFT_SHIFT);
287-
if (enable)
288-
reg |= MII_M1011_PHY_SCR_DOWNSHIFT_EN;
289-
290-
return phy_write(phydev, MII_M1011_PHY_SCR, reg);
291-
}
292-
293279
static int marvell_config_aneg(struct phy_device *phydev)
294280
{
295281
int changed = 0;
@@ -658,41 +644,6 @@ static int marvell_config_init(struct phy_device *phydev)
658644
return marvell_of_reg_init(phydev);
659645
}
660646

661-
static int m88e1116r_config_init(struct phy_device *phydev)
662-
{
663-
int err;
664-
665-
err = genphy_soft_reset(phydev);
666-
if (err < 0)
667-
return err;
668-
669-
msleep(500);
670-
671-
err = marvell_set_page(phydev, MII_MARVELL_COPPER_PAGE);
672-
if (err < 0)
673-
return err;
674-
675-
err = marvell_set_polarity(phydev, phydev->mdix_ctrl);
676-
if (err < 0)
677-
return err;
678-
679-
err = marvell_set_downshift(phydev, true, 8);
680-
if (err < 0)
681-
return err;
682-
683-
if (phy_interface_is_rgmii(phydev)) {
684-
err = m88e1121_config_aneg_rgmii_delays(phydev);
685-
if (err < 0)
686-
return err;
687-
}
688-
689-
err = genphy_soft_reset(phydev);
690-
if (err < 0)
691-
return err;
692-
693-
return marvell_config_init(phydev);
694-
}
695-
696647
static int m88e3016_config_init(struct phy_device *phydev)
697648
{
698649
int ret;
@@ -833,6 +784,114 @@ static int m88e1111_config_init(struct phy_device *phydev)
833784
return genphy_soft_reset(phydev);
834785
}
835786

787+
static int m88e1111_get_downshift(struct phy_device *phydev, u8 *data)
788+
{
789+
int val, cnt, enable;
790+
791+
val = phy_read(phydev, MII_M1011_PHY_SCR);
792+
if (val < 0)
793+
return val;
794+
795+
enable = FIELD_GET(MII_M1011_PHY_SCR_DOWNSHIFT_EN, val);
796+
cnt = FIELD_GET(MII_M1011_PHY_SRC_DOWNSHIFT_MASK, val) + 1;
797+
798+
*data = enable ? cnt : DOWNSHIFT_DEV_DISABLE;
799+
800+
return 0;
801+
}
802+
803+
static int m88e1111_set_downshift(struct phy_device *phydev, u8 cnt)
804+
{
805+
int val;
806+
807+
if (cnt > MII_M1011_PHY_SCR_DOWNSHIFT_MAX)
808+
return -E2BIG;
809+
810+
if (!cnt)
811+
return phy_clear_bits(phydev, MII_M1011_PHY_SCR,
812+
MII_M1011_PHY_SCR_DOWNSHIFT_EN);
813+
814+
val = MII_M1011_PHY_SCR_DOWNSHIFT_EN;
815+
val |= FIELD_PREP(MII_M1011_PHY_SRC_DOWNSHIFT_MASK, cnt - 1);
816+
817+
return phy_modify(phydev, MII_M1011_PHY_SCR,
818+
MII_M1011_PHY_SCR_DOWNSHIFT_EN |
819+
MII_M1011_PHY_SRC_DOWNSHIFT_MASK,
820+
val);
821+
}
822+
823+
static int m88e1111_get_tunable(struct phy_device *phydev,
824+
struct ethtool_tunable *tuna, void *data)
825+
{
826+
switch (tuna->id) {
827+
case ETHTOOL_PHY_DOWNSHIFT:
828+
return m88e1111_get_downshift(phydev, data);
829+
default:
830+
return -EOPNOTSUPP;
831+
}
832+
}
833+
834+
static int m88e1111_set_tunable(struct phy_device *phydev,
835+
struct ethtool_tunable *tuna, const void *data)
836+
{
837+
switch (tuna->id) {
838+
case ETHTOOL_PHY_DOWNSHIFT:
839+
return m88e1111_set_downshift(phydev, *(const u8 *)data);
840+
default:
841+
return -EOPNOTSUPP;
842+
}
843+
}
844+
845+
static void m88e1111_link_change_notify(struct phy_device *phydev)
846+
{
847+
int status;
848+
849+
if (phydev->state != PHY_RUNNING)
850+
return;
851+
852+
/* we may be on fiber page currently */
853+
status = phy_read_paged(phydev, MII_MARVELL_COPPER_PAGE,
854+
MII_M1011_PHY_SSR);
855+
856+
if (status > 0 && status & MII_M1011_PHY_SSR_DOWNSHIFT)
857+
phydev_warn(phydev, "Downshift occurred! Cabling may be defective.\n");
858+
}
859+
860+
static int m88e1116r_config_init(struct phy_device *phydev)
861+
{
862+
int err;
863+
864+
err = genphy_soft_reset(phydev);
865+
if (err < 0)
866+
return err;
867+
868+
msleep(500);
869+
870+
err = marvell_set_page(phydev, MII_MARVELL_COPPER_PAGE);
871+
if (err < 0)
872+
return err;
873+
874+
err = marvell_set_polarity(phydev, phydev->mdix_ctrl);
875+
if (err < 0)
876+
return err;
877+
878+
err = m88e1111_set_downshift(phydev, 8);
879+
if (err < 0)
880+
return err;
881+
882+
if (phy_interface_is_rgmii(phydev)) {
883+
err = m88e1121_config_aneg_rgmii_delays(phydev);
884+
if (err < 0)
885+
return err;
886+
}
887+
888+
err = genphy_soft_reset(phydev);
889+
if (err < 0)
890+
return err;
891+
892+
return marvell_config_init(phydev);
893+
}
894+
836895
static int m88e1318_config_init(struct phy_device *phydev)
837896
{
838897
if (phy_interrupt_is_valid(phydev)) {
@@ -1117,6 +1176,8 @@ static int m88e1540_get_tunable(struct phy_device *phydev,
11171176
switch (tuna->id) {
11181177
case ETHTOOL_PHY_FAST_LINK_DOWN:
11191178
return m88e1540_get_fld(phydev, data);
1179+
case ETHTOOL_PHY_DOWNSHIFT:
1180+
return m88e1111_get_downshift(phydev, data);
11201181
default:
11211182
return -EOPNOTSUPP;
11221183
}
@@ -1128,6 +1189,8 @@ static int m88e1540_set_tunable(struct phy_device *phydev,
11281189
switch (tuna->id) {
11291190
case ETHTOOL_PHY_FAST_LINK_DOWN:
11301191
return m88e1540_set_fld(phydev, data);
1192+
case ETHTOOL_PHY_DOWNSHIFT:
1193+
return m88e1111_set_downshift(phydev, *(const u8 *)data);
11311194
default:
11321195
return -EOPNOTSUPP;
11331196
}
@@ -2220,6 +2283,9 @@ static struct phy_driver marvell_drivers[] = {
22202283
.get_sset_count = marvell_get_sset_count,
22212284
.get_strings = marvell_get_strings,
22222285
.get_stats = marvell_get_stats,
2286+
.get_tunable = m88e1111_get_tunable,
2287+
.set_tunable = m88e1111_set_tunable,
2288+
.link_change_notify = m88e1111_link_change_notify,
22232289
},
22242290
{
22252291
.phy_id = MARVELL_PHY_ID_88E1318S,
@@ -2359,6 +2425,7 @@ static struct phy_driver marvell_drivers[] = {
23592425
.get_stats = marvell_get_stats,
23602426
.get_tunable = m88e1540_get_tunable,
23612427
.set_tunable = m88e1540_set_tunable,
2428+
.link_change_notify = m88e1111_link_change_notify,
23622429
},
23632430
{
23642431
.phy_id = MARVELL_PHY_ID_88E1545,
@@ -2421,6 +2488,7 @@ static struct phy_driver marvell_drivers[] = {
24212488
.get_stats = marvell_get_stats,
24222489
.get_tunable = m88e1540_get_tunable,
24232490
.set_tunable = m88e1540_set_tunable,
2491+
.link_change_notify = m88e1111_link_change_notify,
24242492
},
24252493
};
24262494

0 commit comments

Comments
 (0)