diff options
Diffstat (limited to 'drivers/net/phy/phy.c')
-rw-r--r-- | drivers/net/phy/phy.c | 316 |
1 files changed, 298 insertions, 18 deletions
diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c index 3cbda0851f83..7ca2ff97c368 100644 --- a/drivers/net/phy/phy.c +++ b/drivers/net/phy/phy.c | |||
@@ -15,6 +15,9 @@ | |||
15 | * option) any later version. | 15 | * option) any later version. |
16 | * | 16 | * |
17 | */ | 17 | */ |
18 | |||
19 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt | ||
20 | |||
18 | #include <linux/kernel.h> | 21 | #include <linux/kernel.h> |
19 | #include <linux/string.h> | 22 | #include <linux/string.h> |
20 | #include <linux/errno.h> | 23 | #include <linux/errno.h> |
@@ -32,6 +35,7 @@ | |||
32 | #include <linux/phy.h> | 35 | #include <linux/phy.h> |
33 | #include <linux/timer.h> | 36 | #include <linux/timer.h> |
34 | #include <linux/workqueue.h> | 37 | #include <linux/workqueue.h> |
38 | #include <linux/mdio.h> | ||
35 | 39 | ||
36 | #include <linux/atomic.h> | 40 | #include <linux/atomic.h> |
37 | #include <asm/io.h> | 41 | #include <asm/io.h> |
@@ -44,18 +48,16 @@ | |||
44 | */ | 48 | */ |
45 | void phy_print_status(struct phy_device *phydev) | 49 | void phy_print_status(struct phy_device *phydev) |
46 | { | 50 | { |
47 | pr_info("PHY: %s - Link is %s", dev_name(&phydev->dev), | ||
48 | phydev->link ? "Up" : "Down"); | ||
49 | if (phydev->link) | 51 | if (phydev->link) |
50 | printk(KERN_CONT " - %d/%s", phydev->speed, | 52 | pr_info("%s - Link is Up - %d/%s\n", |
51 | DUPLEX_FULL == phydev->duplex ? | 53 | dev_name(&phydev->dev), |
52 | "Full" : "Half"); | 54 | phydev->speed, |
53 | 55 | DUPLEX_FULL == phydev->duplex ? "Full" : "Half"); | |
54 | printk(KERN_CONT "\n"); | 56 | else |
57 | pr_info("%s - Link is Down\n", dev_name(&phydev->dev)); | ||
55 | } | 58 | } |
56 | EXPORT_SYMBOL(phy_print_status); | 59 | EXPORT_SYMBOL(phy_print_status); |
57 | 60 | ||
58 | |||
59 | /** | 61 | /** |
60 | * phy_clear_interrupt - Ack the phy device's interrupt | 62 | * phy_clear_interrupt - Ack the phy device's interrupt |
61 | * @phydev: the phy_device struct | 63 | * @phydev: the phy_device struct |
@@ -482,9 +484,8 @@ static void phy_force_reduction(struct phy_device *phydev) | |||
482 | phydev->speed = settings[idx].speed; | 484 | phydev->speed = settings[idx].speed; |
483 | phydev->duplex = settings[idx].duplex; | 485 | phydev->duplex = settings[idx].duplex; |
484 | 486 | ||
485 | pr_info("Trying %d/%s\n", phydev->speed, | 487 | pr_info("Trying %d/%s\n", |
486 | DUPLEX_FULL == phydev->duplex ? | 488 | phydev->speed, DUPLEX_FULL == phydev->duplex ? "FULL" : "HALF"); |
487 | "FULL" : "HALF"); | ||
488 | } | 489 | } |
489 | 490 | ||
490 | 491 | ||
@@ -598,9 +599,8 @@ int phy_start_interrupts(struct phy_device *phydev) | |||
598 | IRQF_SHARED, | 599 | IRQF_SHARED, |
599 | "phy_interrupt", | 600 | "phy_interrupt", |
600 | phydev) < 0) { | 601 | phydev) < 0) { |
601 | printk(KERN_WARNING "%s: Can't get IRQ %d (PHY)\n", | 602 | pr_warn("%s: Can't get IRQ %d (PHY)\n", |
602 | phydev->bus->name, | 603 | phydev->bus->name, phydev->irq); |
603 | phydev->irq); | ||
604 | phydev->irq = PHY_POLL; | 604 | phydev->irq = PHY_POLL; |
605 | return 0; | 605 | return 0; |
606 | } | 606 | } |
@@ -838,10 +838,10 @@ void phy_state_machine(struct work_struct *work) | |||
838 | 838 | ||
839 | phydev->autoneg = AUTONEG_DISABLE; | 839 | phydev->autoneg = AUTONEG_DISABLE; |
840 | 840 | ||
841 | pr_info("Trying %d/%s\n", phydev->speed, | 841 | pr_info("Trying %d/%s\n", |
842 | DUPLEX_FULL == | 842 | phydev->speed, |
843 | phydev->duplex ? | 843 | DUPLEX_FULL == phydev->duplex ? |
844 | "FULL" : "HALF"); | 844 | "FULL" : "HALF"); |
845 | } | 845 | } |
846 | break; | 846 | break; |
847 | case PHY_NOLINK: | 847 | case PHY_NOLINK: |
@@ -968,3 +968,283 @@ void phy_state_machine(struct work_struct *work) | |||
968 | 968 | ||
969 | schedule_delayed_work(&phydev->state_queue, PHY_STATE_TIME * HZ); | 969 | schedule_delayed_work(&phydev->state_queue, PHY_STATE_TIME * HZ); |
970 | } | 970 | } |
971 | |||
972 | static inline void mmd_phy_indirect(struct mii_bus *bus, int prtad, int devad, | ||
973 | int addr) | ||
974 | { | ||
975 | /* Write the desired MMD Devad */ | ||
976 | bus->write(bus, addr, MII_MMD_CTRL, devad); | ||
977 | |||
978 | /* Write the desired MMD register address */ | ||
979 | bus->write(bus, addr, MII_MMD_DATA, prtad); | ||
980 | |||
981 | /* Select the Function : DATA with no post increment */ | ||
982 | bus->write(bus, addr, MII_MMD_CTRL, (devad | MII_MMD_CTRL_NOINCR)); | ||
983 | } | ||
984 | |||
985 | /** | ||
986 | * phy_read_mmd_indirect - reads data from the MMD registers | ||
987 | * @bus: the target MII bus | ||
988 | * @prtad: MMD Address | ||
989 | * @devad: MMD DEVAD | ||
990 | * @addr: PHY address on the MII bus | ||
991 | * | ||
992 | * Description: it reads data from the MMD registers (clause 22 to access to | ||
993 | * clause 45) of the specified phy address. | ||
994 | * To read these register we have: | ||
995 | * 1) Write reg 13 // DEVAD | ||
996 | * 2) Write reg 14 // MMD Address | ||
997 | * 3) Write reg 13 // MMD Data Command for MMD DEVAD | ||
998 | * 3) Read reg 14 // Read MMD data | ||
999 | */ | ||
1000 | static int phy_read_mmd_indirect(struct mii_bus *bus, int prtad, int devad, | ||
1001 | int addr) | ||
1002 | { | ||
1003 | u32 ret; | ||
1004 | |||
1005 | mmd_phy_indirect(bus, prtad, devad, addr); | ||
1006 | |||
1007 | /* Read the content of the MMD's selected register */ | ||
1008 | ret = bus->read(bus, addr, MII_MMD_DATA); | ||
1009 | |||
1010 | return ret; | ||
1011 | } | ||
1012 | |||
1013 | /** | ||
1014 | * phy_write_mmd_indirect - writes data to the MMD registers | ||
1015 | * @bus: the target MII bus | ||
1016 | * @prtad: MMD Address | ||
1017 | * @devad: MMD DEVAD | ||
1018 | * @addr: PHY address on the MII bus | ||
1019 | * @data: data to write in the MMD register | ||
1020 | * | ||
1021 | * Description: Write data from the MMD registers of the specified | ||
1022 | * phy address. | ||
1023 | * To write these register we have: | ||
1024 | * 1) Write reg 13 // DEVAD | ||
1025 | * 2) Write reg 14 // MMD Address | ||
1026 | * 3) Write reg 13 // MMD Data Command for MMD DEVAD | ||
1027 | * 3) Write reg 14 // Write MMD data | ||
1028 | */ | ||
1029 | static void phy_write_mmd_indirect(struct mii_bus *bus, int prtad, int devad, | ||
1030 | int addr, u32 data) | ||
1031 | { | ||
1032 | mmd_phy_indirect(bus, prtad, devad, addr); | ||
1033 | |||
1034 | /* Write the data into MMD's selected register */ | ||
1035 | bus->write(bus, addr, MII_MMD_DATA, data); | ||
1036 | } | ||
1037 | |||
1038 | static u32 phy_eee_to_adv(u16 eee_adv) | ||
1039 | { | ||
1040 | u32 adv = 0; | ||
1041 | |||
1042 | if (eee_adv & MDIO_EEE_100TX) | ||
1043 | adv |= ADVERTISED_100baseT_Full; | ||
1044 | if (eee_adv & MDIO_EEE_1000T) | ||
1045 | adv |= ADVERTISED_1000baseT_Full; | ||
1046 | if (eee_adv & MDIO_EEE_10GT) | ||
1047 | adv |= ADVERTISED_10000baseT_Full; | ||
1048 | if (eee_adv & MDIO_EEE_1000KX) | ||
1049 | adv |= ADVERTISED_1000baseKX_Full; | ||
1050 | if (eee_adv & MDIO_EEE_10GKX4) | ||
1051 | adv |= ADVERTISED_10000baseKX4_Full; | ||
1052 | if (eee_adv & MDIO_EEE_10GKR) | ||
1053 | adv |= ADVERTISED_10000baseKR_Full; | ||
1054 | |||
1055 | return adv; | ||
1056 | } | ||
1057 | |||
1058 | static u32 phy_eee_to_supported(u16 eee_caported) | ||
1059 | { | ||
1060 | u32 supported = 0; | ||
1061 | |||
1062 | if (eee_caported & MDIO_EEE_100TX) | ||
1063 | supported |= SUPPORTED_100baseT_Full; | ||
1064 | if (eee_caported & MDIO_EEE_1000T) | ||
1065 | supported |= SUPPORTED_1000baseT_Full; | ||
1066 | if (eee_caported & MDIO_EEE_10GT) | ||
1067 | supported |= SUPPORTED_10000baseT_Full; | ||
1068 | if (eee_caported & MDIO_EEE_1000KX) | ||
1069 | supported |= SUPPORTED_1000baseKX_Full; | ||
1070 | if (eee_caported & MDIO_EEE_10GKX4) | ||
1071 | supported |= SUPPORTED_10000baseKX4_Full; | ||
1072 | if (eee_caported & MDIO_EEE_10GKR) | ||
1073 | supported |= SUPPORTED_10000baseKR_Full; | ||
1074 | |||
1075 | return supported; | ||
1076 | } | ||
1077 | |||
1078 | static u16 phy_adv_to_eee(u32 adv) | ||
1079 | { | ||
1080 | u16 reg = 0; | ||
1081 | |||
1082 | if (adv & ADVERTISED_100baseT_Full) | ||
1083 | reg |= MDIO_EEE_100TX; | ||
1084 | if (adv & ADVERTISED_1000baseT_Full) | ||
1085 | reg |= MDIO_EEE_1000T; | ||
1086 | if (adv & ADVERTISED_10000baseT_Full) | ||
1087 | reg |= MDIO_EEE_10GT; | ||
1088 | if (adv & ADVERTISED_1000baseKX_Full) | ||
1089 | reg |= MDIO_EEE_1000KX; | ||
1090 | if (adv & ADVERTISED_10000baseKX4_Full) | ||
1091 | reg |= MDIO_EEE_10GKX4; | ||
1092 | if (adv & ADVERTISED_10000baseKR_Full) | ||
1093 | reg |= MDIO_EEE_10GKR; | ||
1094 | |||
1095 | return reg; | ||
1096 | } | ||
1097 | |||
1098 | /** | ||
1099 | * phy_init_eee - init and check the EEE feature | ||
1100 | * @phydev: target phy_device struct | ||
1101 | * @clk_stop_enable: PHY may stop the clock during LPI | ||
1102 | * | ||
1103 | * Description: it checks if the Energy-Efficient Ethernet (EEE) | ||
1104 | * is supported by looking at the MMD registers 3.20 and 7.60/61 | ||
1105 | * and it programs the MMD register 3.0 setting the "Clock stop enable" | ||
1106 | * bit if required. | ||
1107 | */ | ||
1108 | int phy_init_eee(struct phy_device *phydev, bool clk_stop_enable) | ||
1109 | { | ||
1110 | int ret = -EPROTONOSUPPORT; | ||
1111 | |||
1112 | /* According to 802.3az,the EEE is supported only in full duplex-mode. | ||
1113 | * Also EEE feature is active when core is operating with MII, GMII | ||
1114 | * or RGMII. | ||
1115 | */ | ||
1116 | if ((phydev->duplex == DUPLEX_FULL) && | ||
1117 | ((phydev->interface == PHY_INTERFACE_MODE_MII) || | ||
1118 | (phydev->interface == PHY_INTERFACE_MODE_GMII) || | ||
1119 | (phydev->interface == PHY_INTERFACE_MODE_RGMII))) { | ||
1120 | int eee_lp, eee_cap, eee_adv; | ||
1121 | u32 lp, cap, adv; | ||
1122 | int idx, status; | ||
1123 | |||
1124 | /* Read phy status to properly get the right settings */ | ||
1125 | status = phy_read_status(phydev); | ||
1126 | if (status) | ||
1127 | return status; | ||
1128 | |||
1129 | /* First check if the EEE ability is supported */ | ||
1130 | eee_cap = phy_read_mmd_indirect(phydev->bus, MDIO_PCS_EEE_ABLE, | ||
1131 | MDIO_MMD_PCS, phydev->addr); | ||
1132 | if (eee_cap < 0) | ||
1133 | return eee_cap; | ||
1134 | |||
1135 | cap = phy_eee_to_supported(eee_cap); | ||
1136 | if (!cap) | ||
1137 | goto eee_exit; | ||
1138 | |||
1139 | /* Check which link settings negotiated and verify it in | ||
1140 | * the EEE advertising registers. | ||
1141 | */ | ||
1142 | eee_lp = phy_read_mmd_indirect(phydev->bus, MDIO_AN_EEE_LPABLE, | ||
1143 | MDIO_MMD_AN, phydev->addr); | ||
1144 | if (eee_lp < 0) | ||
1145 | return eee_lp; | ||
1146 | |||
1147 | eee_adv = phy_read_mmd_indirect(phydev->bus, MDIO_AN_EEE_ADV, | ||
1148 | MDIO_MMD_AN, phydev->addr); | ||
1149 | if (eee_adv < 0) | ||
1150 | return eee_adv; | ||
1151 | |||
1152 | adv = phy_eee_to_adv(eee_adv); | ||
1153 | lp = phy_eee_to_adv(eee_lp); | ||
1154 | idx = phy_find_setting(phydev->speed, phydev->duplex); | ||
1155 | if ((lp & adv & settings[idx].setting)) | ||
1156 | goto eee_exit; | ||
1157 | |||
1158 | if (clk_stop_enable) { | ||
1159 | /* Configure the PHY to stop receiving xMII | ||
1160 | * clock while it is signaling LPI. | ||
1161 | */ | ||
1162 | int val = phy_read_mmd_indirect(phydev->bus, MDIO_CTRL1, | ||
1163 | MDIO_MMD_PCS, | ||
1164 | phydev->addr); | ||
1165 | if (val < 0) | ||
1166 | return val; | ||
1167 | |||
1168 | val |= MDIO_PCS_CTRL1_CLKSTOP_EN; | ||
1169 | phy_write_mmd_indirect(phydev->bus, MDIO_CTRL1, | ||
1170 | MDIO_MMD_PCS, phydev->addr, val); | ||
1171 | } | ||
1172 | |||
1173 | ret = 0; /* EEE supported */ | ||
1174 | } | ||
1175 | |||
1176 | eee_exit: | ||
1177 | return ret; | ||
1178 | } | ||
1179 | EXPORT_SYMBOL(phy_init_eee); | ||
1180 | |||
1181 | /** | ||
1182 | * phy_get_eee_err - report the EEE wake error count | ||
1183 | * @phydev: target phy_device struct | ||
1184 | * | ||
1185 | * Description: it is to report the number of time where the PHY | ||
1186 | * failed to complete its normal wake sequence. | ||
1187 | */ | ||
1188 | int phy_get_eee_err(struct phy_device *phydev) | ||
1189 | { | ||
1190 | return phy_read_mmd_indirect(phydev->bus, MDIO_PCS_EEE_WK_ERR, | ||
1191 | MDIO_MMD_PCS, phydev->addr); | ||
1192 | |||
1193 | } | ||
1194 | EXPORT_SYMBOL(phy_get_eee_err); | ||
1195 | |||
1196 | /** | ||
1197 | * phy_ethtool_get_eee - get EEE supported and status | ||
1198 | * @phydev: target phy_device struct | ||
1199 | * @data: ethtool_eee data | ||
1200 | * | ||
1201 | * Description: it reportes the Supported/Advertisement/LP Advertisement | ||
1202 | * capabilities. | ||
1203 | */ | ||
1204 | int phy_ethtool_get_eee(struct phy_device *phydev, struct ethtool_eee *data) | ||
1205 | { | ||
1206 | int val; | ||
1207 | |||
1208 | /* Get Supported EEE */ | ||
1209 | val = phy_read_mmd_indirect(phydev->bus, MDIO_PCS_EEE_ABLE, | ||
1210 | MDIO_MMD_PCS, phydev->addr); | ||
1211 | if (val < 0) | ||
1212 | return val; | ||
1213 | data->supported = phy_eee_to_supported(val); | ||
1214 | |||
1215 | /* Get advertisement EEE */ | ||
1216 | val = phy_read_mmd_indirect(phydev->bus, MDIO_AN_EEE_ADV, | ||
1217 | MDIO_MMD_AN, phydev->addr); | ||
1218 | if (val < 0) | ||
1219 | return val; | ||
1220 | data->advertised = phy_eee_to_adv(val); | ||
1221 | |||
1222 | /* Get LP advertisement EEE */ | ||
1223 | val = phy_read_mmd_indirect(phydev->bus, MDIO_AN_EEE_LPABLE, | ||
1224 | MDIO_MMD_AN, phydev->addr); | ||
1225 | if (val < 0) | ||
1226 | return val; | ||
1227 | data->lp_advertised = phy_eee_to_adv(val); | ||
1228 | |||
1229 | return 0; | ||
1230 | } | ||
1231 | EXPORT_SYMBOL(phy_ethtool_get_eee); | ||
1232 | |||
1233 | /** | ||
1234 | * phy_ethtool_set_eee - set EEE supported and status | ||
1235 | * @phydev: target phy_device struct | ||
1236 | * @data: ethtool_eee data | ||
1237 | * | ||
1238 | * Description: it is to program the Advertisement EEE register. | ||
1239 | */ | ||
1240 | int phy_ethtool_set_eee(struct phy_device *phydev, struct ethtool_eee *data) | ||
1241 | { | ||
1242 | int val; | ||
1243 | |||
1244 | val = phy_adv_to_eee(data->advertised); | ||
1245 | phy_write_mmd_indirect(phydev->bus, MDIO_AN_EEE_ADV, MDIO_MMD_AN, | ||
1246 | phydev->addr, val); | ||
1247 | |||
1248 | return 0; | ||
1249 | } | ||
1250 | EXPORT_SYMBOL(phy_ethtool_set_eee); | ||