aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid S. Miller <davem@davemloft.net>2014-07-30 23:00:27 -0400
committerDavid S. Miller <davem@davemloft.net>2014-07-30 23:00:27 -0400
commit989e9ad0c40862003a6bd85b4a3db45d49246e09 (patch)
treef1b7d87f00ab699c665418eee323acced26ac83f
parent9e6492ec99c24b88a7c57623e5664d389261bf4e (diff)
parent49193a66f00148443288a83c6ac377a641b10bd5 (diff)
Merge branch 'libphy_mmd'
Vince Bridgers says: ==================== net: libphy: Add phy specific functions to access mmd regs This set of patches addresses a problem found with the Micrel ksz9021 phy and libphy, where the ksz9021 phy does not support mmd extended register access per the IEEE specification as assumed by libphy. The first patch adds a framework for phy specific support to specify their own function to access extended phy registers, return a failure code if not supported, or to default to libphy's IEEE defined method for accessing the mmd extended phy registers. This issue was found by using the Synopsys EMAC and a Micrel ksz9021 phy on the Altera Cyclone 5 SOC development kit. This patch was tested on the same system in both positive and negative test cases. V5: Revert name of mmd register access functions, check for phy specific driver override functions in mmd register access functions per Florian's comments to minimize source code changes V4: Correct error when formatting V3 patch - erroneous text cut from code V3: Correct formatting of function arguments, remove return statement from NULL functions, and add patch for PHY driver documentation per review comments. V2: Split the original patch submission into seperate patches for the libphy framework required for the modification and for the Micrel Phy. ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--Documentation/networking/phy.txt18
-rw-r--r--drivers/net/phy/micrel.c22
-rw-r--r--drivers/net/phy/phy.c61
-rw-r--r--include/linux/phy.h18
4 files changed, 95 insertions, 24 deletions
diff --git a/Documentation/networking/phy.txt b/Documentation/networking/phy.txt
index 3544c98401fd..e839e7efc835 100644
--- a/Documentation/networking/phy.txt
+++ b/Documentation/networking/phy.txt
@@ -272,6 +272,8 @@ Writing a PHY driver
272 txtsamp: Requests a transmit timestamp at the PHY level for a 'skb' 272 txtsamp: Requests a transmit timestamp at the PHY level for a 'skb'
273 set_wol: Enable Wake-on-LAN at the PHY level 273 set_wol: Enable Wake-on-LAN at the PHY level
274 get_wol: Get the Wake-on-LAN status at the PHY level 274 get_wol: Get the Wake-on-LAN status at the PHY level
275 read_mmd_indirect: Read PHY MMD indirect register
276 write_mmd_indirect: Write PHY MMD indirect register
275 277
276 Of these, only config_aneg and read_status are required to be 278 Of these, only config_aneg and read_status are required to be
277 assigned by the driver code. The rest are optional. Also, it is 279 assigned by the driver code. The rest are optional. Also, it is
@@ -284,7 +286,21 @@ Writing a PHY driver
284 286
285 Feel free to look at the Marvell, Cicada, and Davicom drivers in 287 Feel free to look at the Marvell, Cicada, and Davicom drivers in
286 drivers/net/phy/ for examples (the lxt and qsemi drivers have 288 drivers/net/phy/ for examples (the lxt and qsemi drivers have
287 not been tested as of this writing) 289 not been tested as of this writing).
290
291 The PHY's MMD register accesses are handled by the PAL framework
292 by default, but can be overridden by a specific PHY driver if
293 required. This could be the case if a PHY was released for
294 manufacturing before the MMD PHY register definitions were
295 standardized by the IEEE. Most modern PHYs will be able to use
296 the generic PAL framework for accessing the PHY's MMD registers.
297 An example of such usage is for Energy Efficient Ethernet support,
298 implemented in the PAL. This support uses the PAL to access MMD
299 registers for EEE query and configuration if the PHY supports
300 the IEEE standard access mechanisms, or can use the PHY's specific
301 access interfaces if overridden by the specific PHY driver. See
302 the Micrel driver in drivers/net/phy/ for an example of how this
303 can be implemented.
288 304
289Board Fixups 305Board Fixups
290 306
diff --git a/drivers/net/phy/micrel.c b/drivers/net/phy/micrel.c
index bc7c7d2f75f2..fd0ea7c50ee6 100644
--- a/drivers/net/phy/micrel.c
+++ b/drivers/net/phy/micrel.c
@@ -420,6 +420,26 @@ static int ksz8873mll_config_aneg(struct phy_device *phydev)
420 return 0; 420 return 0;
421} 421}
422 422
423/* This routine returns -1 as an indication to the caller that the
424 * Micrel ksz9021 10/100/1000 PHY does not support standard IEEE
425 * MMD extended PHY registers.
426 */
427static int
428ksz9021_rd_mmd_phyreg(struct phy_device *phydev, int ptrad, int devnum,
429 int regnum)
430{
431 return -1;
432}
433
434/* This routine does nothing since the Micrel ksz9021 does not support
435 * standard IEEE MMD extended PHY registers.
436 */
437static void
438ksz9021_wr_mmd_phyreg(struct phy_device *phydev, int ptrad, int devnum,
439 int regnum, u32 val)
440{
441}
442
423static struct phy_driver ksphy_driver[] = { 443static struct phy_driver ksphy_driver[] = {
424{ 444{
425 .phy_id = PHY_ID_KS8737, 445 .phy_id = PHY_ID_KS8737,
@@ -565,6 +585,8 @@ static struct phy_driver ksphy_driver[] = {
565 .config_intr = ksz9021_config_intr, 585 .config_intr = ksz9021_config_intr,
566 .suspend = genphy_suspend, 586 .suspend = genphy_suspend,
567 .resume = genphy_resume, 587 .resume = genphy_resume,
588 .read_mmd_indirect = ksz9021_rd_mmd_phyreg,
589 .write_mmd_indirect = ksz9021_wr_mmd_phyreg,
568 .driver = { .owner = THIS_MODULE, }, 590 .driver = { .owner = THIS_MODULE, },
569}, { 591}, {
570 .phy_id = PHY_ID_KSZ9031, 592 .phy_id = PHY_ID_KSZ9031,
diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c
index e56e269a6eb3..c94e2a27446a 100644
--- a/drivers/net/phy/phy.c
+++ b/drivers/net/phy/phy.c
@@ -942,7 +942,7 @@ static inline void mmd_phy_indirect(struct mii_bus *bus, int prtad, int devad,
942 942
943/** 943/**
944 * phy_read_mmd_indirect - reads data from the MMD registers 944 * phy_read_mmd_indirect - reads data from the MMD registers
945 * @bus: the target MII bus 945 * @phydev: The PHY device bus
946 * @prtad: MMD Address 946 * @prtad: MMD Address
947 * @devad: MMD DEVAD 947 * @devad: MMD DEVAD
948 * @addr: PHY address on the MII bus 948 * @addr: PHY address on the MII bus
@@ -955,18 +955,26 @@ static inline void mmd_phy_indirect(struct mii_bus *bus, int prtad, int devad,
955 * 3) Write reg 13 // MMD Data Command for MMD DEVAD 955 * 3) Write reg 13 // MMD Data Command for MMD DEVAD
956 * 3) Read reg 14 // Read MMD data 956 * 3) Read reg 14 // Read MMD data
957 */ 957 */
958static int phy_read_mmd_indirect(struct mii_bus *bus, int prtad, int devad, 958static int phy_read_mmd_indirect(struct phy_device *phydev, int prtad,
959 int addr) 959 int devad, int addr)
960{ 960{
961 mmd_phy_indirect(bus, prtad, devad, addr); 961 struct phy_driver *phydrv = phydev->drv;
962 int value = -1;
962 963
963 /* Read the content of the MMD's selected register */ 964 if (phydrv->read_mmd_indirect == NULL) {
964 return bus->read(bus, addr, MII_MMD_DATA); 965 mmd_phy_indirect(phydev->bus, prtad, devad, addr);
966
967 /* Read the content of the MMD's selected register */
968 value = phydev->bus->read(phydev->bus, addr, MII_MMD_DATA);
969 } else {
970 value = phydrv->read_mmd_indirect(phydev, prtad, devad, addr);
971 }
972 return value;
965} 973}
966 974
967/** 975/**
968 * phy_write_mmd_indirect - writes data to the MMD registers 976 * phy_write_mmd_indirect - writes data to the MMD registers
969 * @bus: the target MII bus 977 * @phydev: The PHY device
970 * @prtad: MMD Address 978 * @prtad: MMD Address
971 * @devad: MMD DEVAD 979 * @devad: MMD DEVAD
972 * @addr: PHY address on the MII bus 980 * @addr: PHY address on the MII bus
@@ -980,13 +988,19 @@ static int phy_read_mmd_indirect(struct mii_bus *bus, int prtad, int devad,
980 * 3) Write reg 13 // MMD Data Command for MMD DEVAD 988 * 3) Write reg 13 // MMD Data Command for MMD DEVAD
981 * 3) Write reg 14 // Write MMD data 989 * 3) Write reg 14 // Write MMD data
982 */ 990 */
983static void phy_write_mmd_indirect(struct mii_bus *bus, int prtad, int devad, 991static void phy_write_mmd_indirect(struct phy_device *phydev, int prtad,
984 int addr, u32 data) 992 int devad, int addr, u32 data)
985{ 993{
986 mmd_phy_indirect(bus, prtad, devad, addr); 994 struct phy_driver *phydrv = phydev->drv;
987 995
988 /* Write the data into MMD's selected register */ 996 if (phydrv->write_mmd_indirect == NULL) {
989 bus->write(bus, addr, MII_MMD_DATA, data); 997 mmd_phy_indirect(phydev->bus, prtad, devad, addr);
998
999 /* Write the data into MMD's selected register */
1000 phydev->bus->write(phydev->bus, addr, MII_MMD_DATA, data);
1001 } else {
1002 phydrv->write_mmd_indirect(phydev, prtad, devad, addr, data);
1003 }
990} 1004}
991 1005
992/** 1006/**
@@ -1020,7 +1034,7 @@ int phy_init_eee(struct phy_device *phydev, bool clk_stop_enable)
1020 return status; 1034 return status;
1021 1035
1022 /* First check if the EEE ability is supported */ 1036 /* First check if the EEE ability is supported */
1023 eee_cap = phy_read_mmd_indirect(phydev->bus, MDIO_PCS_EEE_ABLE, 1037 eee_cap = phy_read_mmd_indirect(phydev, MDIO_PCS_EEE_ABLE,
1024 MDIO_MMD_PCS, phydev->addr); 1038 MDIO_MMD_PCS, phydev->addr);
1025 if (eee_cap < 0) 1039 if (eee_cap < 0)
1026 return eee_cap; 1040 return eee_cap;
@@ -1032,12 +1046,12 @@ int phy_init_eee(struct phy_device *phydev, bool clk_stop_enable)
1032 /* Check which link settings negotiated and verify it in 1046 /* Check which link settings negotiated and verify it in
1033 * the EEE advertising registers. 1047 * the EEE advertising registers.
1034 */ 1048 */
1035 eee_lp = phy_read_mmd_indirect(phydev->bus, MDIO_AN_EEE_LPABLE, 1049 eee_lp = phy_read_mmd_indirect(phydev, MDIO_AN_EEE_LPABLE,
1036 MDIO_MMD_AN, phydev->addr); 1050 MDIO_MMD_AN, phydev->addr);
1037 if (eee_lp < 0) 1051 if (eee_lp < 0)
1038 return eee_lp; 1052 return eee_lp;
1039 1053
1040 eee_adv = phy_read_mmd_indirect(phydev->bus, MDIO_AN_EEE_ADV, 1054 eee_adv = phy_read_mmd_indirect(phydev, MDIO_AN_EEE_ADV,
1041 MDIO_MMD_AN, phydev->addr); 1055 MDIO_MMD_AN, phydev->addr);
1042 if (eee_adv < 0) 1056 if (eee_adv < 0)
1043 return eee_adv; 1057 return eee_adv;
@@ -1052,15 +1066,16 @@ int phy_init_eee(struct phy_device *phydev, bool clk_stop_enable)
1052 /* Configure the PHY to stop receiving xMII 1066 /* Configure the PHY to stop receiving xMII
1053 * clock while it is signaling LPI. 1067 * clock while it is signaling LPI.
1054 */ 1068 */
1055 int val = phy_read_mmd_indirect(phydev->bus, MDIO_CTRL1, 1069 int val = phy_read_mmd_indirect(phydev, MDIO_CTRL1,
1056 MDIO_MMD_PCS, 1070 MDIO_MMD_PCS,
1057 phydev->addr); 1071 phydev->addr);
1058 if (val < 0) 1072 if (val < 0)
1059 return val; 1073 return val;
1060 1074
1061 val |= MDIO_PCS_CTRL1_CLKSTOP_EN; 1075 val |= MDIO_PCS_CTRL1_CLKSTOP_EN;
1062 phy_write_mmd_indirect(phydev->bus, MDIO_CTRL1, 1076 phy_write_mmd_indirect(phydev, MDIO_CTRL1,
1063 MDIO_MMD_PCS, phydev->addr, val); 1077 MDIO_MMD_PCS, phydev->addr,
1078 val);
1064 } 1079 }
1065 1080
1066 return 0; /* EEE supported */ 1081 return 0; /* EEE supported */
@@ -1079,7 +1094,7 @@ EXPORT_SYMBOL(phy_init_eee);
1079 */ 1094 */
1080int phy_get_eee_err(struct phy_device *phydev) 1095int phy_get_eee_err(struct phy_device *phydev)
1081{ 1096{
1082 return phy_read_mmd_indirect(phydev->bus, MDIO_PCS_EEE_WK_ERR, 1097 return phy_read_mmd_indirect(phydev, MDIO_PCS_EEE_WK_ERR,
1083 MDIO_MMD_PCS, phydev->addr); 1098 MDIO_MMD_PCS, phydev->addr);
1084} 1099}
1085EXPORT_SYMBOL(phy_get_eee_err); 1100EXPORT_SYMBOL(phy_get_eee_err);
@@ -1097,21 +1112,21 @@ int phy_ethtool_get_eee(struct phy_device *phydev, struct ethtool_eee *data)
1097 int val; 1112 int val;
1098 1113
1099 /* Get Supported EEE */ 1114 /* Get Supported EEE */
1100 val = phy_read_mmd_indirect(phydev->bus, MDIO_PCS_EEE_ABLE, 1115 val = phy_read_mmd_indirect(phydev, MDIO_PCS_EEE_ABLE,
1101 MDIO_MMD_PCS, phydev->addr); 1116 MDIO_MMD_PCS, phydev->addr);
1102 if (val < 0) 1117 if (val < 0)
1103 return val; 1118 return val;
1104 data->supported = mmd_eee_cap_to_ethtool_sup_t(val); 1119 data->supported = mmd_eee_cap_to_ethtool_sup_t(val);
1105 1120
1106 /* Get advertisement EEE */ 1121 /* Get advertisement EEE */
1107 val = phy_read_mmd_indirect(phydev->bus, MDIO_AN_EEE_ADV, 1122 val = phy_read_mmd_indirect(phydev, MDIO_AN_EEE_ADV,
1108 MDIO_MMD_AN, phydev->addr); 1123 MDIO_MMD_AN, phydev->addr);
1109 if (val < 0) 1124 if (val < 0)
1110 return val; 1125 return val;
1111 data->advertised = mmd_eee_adv_to_ethtool_adv_t(val); 1126 data->advertised = mmd_eee_adv_to_ethtool_adv_t(val);
1112 1127
1113 /* Get LP advertisement EEE */ 1128 /* Get LP advertisement EEE */
1114 val = phy_read_mmd_indirect(phydev->bus, MDIO_AN_EEE_LPABLE, 1129 val = phy_read_mmd_indirect(phydev, MDIO_AN_EEE_LPABLE,
1115 MDIO_MMD_AN, phydev->addr); 1130 MDIO_MMD_AN, phydev->addr);
1116 if (val < 0) 1131 if (val < 0)
1117 return val; 1132 return val;
@@ -1132,7 +1147,7 @@ int phy_ethtool_set_eee(struct phy_device *phydev, struct ethtool_eee *data)
1132{ 1147{
1133 int val = ethtool_adv_to_mmd_eee_adv_t(data->advertised); 1148 int val = ethtool_adv_to_mmd_eee_adv_t(data->advertised);
1134 1149
1135 phy_write_mmd_indirect(phydev->bus, MDIO_AN_EEE_ADV, MDIO_MMD_AN, 1150 phy_write_mmd_indirect(phydev, MDIO_AN_EEE_ADV, MDIO_MMD_AN,
1136 phydev->addr, val); 1151 phydev->addr, val);
1137 1152
1138 return 0; 1153 return 0;
diff --git a/include/linux/phy.h b/include/linux/phy.h
index 68041446c450..ed39956b5613 100644
--- a/include/linux/phy.h
+++ b/include/linux/phy.h
@@ -545,6 +545,24 @@ struct phy_driver {
545 */ 545 */
546 void (*link_change_notify)(struct phy_device *dev); 546 void (*link_change_notify)(struct phy_device *dev);
547 547
548 /* A function provided by a phy specific driver to override the
549 * the PHY driver framework support for reading a MMD register
550 * from the PHY. If not supported, return -1. This function is
551 * optional for PHY specific drivers, if not provided then the
552 * default MMD read function is used by the PHY framework.
553 */
554 int (*read_mmd_indirect)(struct phy_device *dev, int ptrad,
555 int devnum, int regnum);
556
557 /* A function provided by a phy specific driver to override the
558 * the PHY driver framework support for writing a MMD register
559 * from the PHY. This function is optional for PHY specific drivers,
560 * if not provided then the default MMD read function is used by
561 * the PHY framework.
562 */
563 void (*write_mmd_indirect)(struct phy_device *dev, int ptrad,
564 int devnum, int regnum, u32 val);
565
548 struct device_driver driver; 566 struct device_driver driver;
549}; 567};
550#define to_phy_driver(d) container_of(d, struct phy_driver, driver) 568#define to_phy_driver(d) container_of(d, struct phy_driver, driver)