aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/usb
diff options
context:
space:
mode:
authorSteve Glendinning <steve.glendinning@shawell.net>2012-11-22 03:05:24 -0500
committerDavid S. Miller <davem@davemloft.net>2012-11-23 14:15:18 -0500
commite5e3af8348945b7c0b96e720c35309c79c24e98f (patch)
treeae237dd7282e990b4cbb0f59c3a52297ed58c6a3 /drivers/net/usb
parent9ebca5071c8679bba96981af6bc29370f1c2f0aa (diff)
smsc95xx: support PHY wakeup source
This patch enables LAN9500 family devices to wake from suspend on either link up or link down events It also adds _nopm versions of mdio access functions, so we can safely call them from suspend and resume functions Signed-off-by: Steve Glendinning <steve.glendinning@shawell.net> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/usb')
-rw-r--r--drivers/net/usb/smsc95xx.c164
-rw-r--r--drivers/net/usb/smsc95xx.h17
2 files changed, 164 insertions, 17 deletions
diff --git a/drivers/net/usb/smsc95xx.c b/drivers/net/usb/smsc95xx.c
index 3bacb4153f3d..e98ff8c77ec5 100644
--- a/drivers/net/usb/smsc95xx.c
+++ b/drivers/net/usb/smsc95xx.c
@@ -48,7 +48,7 @@
48#define SMSC95XX_INTERNAL_PHY_ID (1) 48#define SMSC95XX_INTERNAL_PHY_ID (1)
49#define SMSC95XX_TX_OVERHEAD (8) 49#define SMSC95XX_TX_OVERHEAD (8)
50#define SMSC95XX_TX_OVERHEAD_CSUM (12) 50#define SMSC95XX_TX_OVERHEAD_CSUM (12)
51#define SUPPORTED_WAKE (WAKE_UCAST | WAKE_BCAST | \ 51#define SUPPORTED_WAKE (WAKE_PHY | WAKE_UCAST | WAKE_BCAST | \
52 WAKE_MCAST | WAKE_ARP | WAKE_MAGIC) 52 WAKE_MCAST | WAKE_ARP | WAKE_MAGIC)
53 53
54#define FEATURE_8_WAKEUP_FILTERS (0x01) 54#define FEATURE_8_WAKEUP_FILTERS (0x01)
@@ -176,14 +176,15 @@ static int smsc95xx_clear_feature(struct usbnet *dev, u32 feature)
176 176
177/* Loop until the read is completed with timeout 177/* Loop until the read is completed with timeout
178 * called with phy_mutex held */ 178 * called with phy_mutex held */
179static int __must_check smsc95xx_phy_wait_not_busy(struct usbnet *dev) 179static int __must_check __smsc95xx_phy_wait_not_busy(struct usbnet *dev,
180 int in_pm)
180{ 181{
181 unsigned long start_time = jiffies; 182 unsigned long start_time = jiffies;
182 u32 val; 183 u32 val;
183 int ret; 184 int ret;
184 185
185 do { 186 do {
186 ret = smsc95xx_read_reg(dev, MII_ADDR, &val); 187 ret = __smsc95xx_read_reg(dev, MII_ADDR, &val, in_pm);
187 check_warn_return(ret, "Error reading MII_ACCESS"); 188 check_warn_return(ret, "Error reading MII_ACCESS");
188 if (!(val & MII_BUSY_)) 189 if (!(val & MII_BUSY_))
189 return 0; 190 return 0;
@@ -192,7 +193,8 @@ static int __must_check smsc95xx_phy_wait_not_busy(struct usbnet *dev)
192 return -EIO; 193 return -EIO;
193} 194}
194 195
195static int smsc95xx_mdio_read(struct net_device *netdev, int phy_id, int idx) 196static int __smsc95xx_mdio_read(struct net_device *netdev, int phy_id, int idx,
197 int in_pm)
196{ 198{
197 struct usbnet *dev = netdev_priv(netdev); 199 struct usbnet *dev = netdev_priv(netdev);
198 u32 val, addr; 200 u32 val, addr;
@@ -201,20 +203,20 @@ static int smsc95xx_mdio_read(struct net_device *netdev, int phy_id, int idx)
201 mutex_lock(&dev->phy_mutex); 203 mutex_lock(&dev->phy_mutex);
202 204
203 /* confirm MII not busy */ 205 /* confirm MII not busy */
204 ret = smsc95xx_phy_wait_not_busy(dev); 206 ret = __smsc95xx_phy_wait_not_busy(dev, in_pm);
205 check_warn_goto_done(ret, "MII is busy in smsc95xx_mdio_read"); 207 check_warn_goto_done(ret, "MII is busy in smsc95xx_mdio_read");
206 208
207 /* set the address, index & direction (read from PHY) */ 209 /* set the address, index & direction (read from PHY) */
208 phy_id &= dev->mii.phy_id_mask; 210 phy_id &= dev->mii.phy_id_mask;
209 idx &= dev->mii.reg_num_mask; 211 idx &= dev->mii.reg_num_mask;
210 addr = (phy_id << 11) | (idx << 6) | MII_READ_ | MII_BUSY_; 212 addr = (phy_id << 11) | (idx << 6) | MII_READ_ | MII_BUSY_;
211 ret = smsc95xx_write_reg(dev, MII_ADDR, addr); 213 ret = __smsc95xx_write_reg(dev, MII_ADDR, addr, in_pm);
212 check_warn_goto_done(ret, "Error writing MII_ADDR"); 214 check_warn_goto_done(ret, "Error writing MII_ADDR");
213 215
214 ret = smsc95xx_phy_wait_not_busy(dev); 216 ret = __smsc95xx_phy_wait_not_busy(dev, in_pm);
215 check_warn_goto_done(ret, "Timed out reading MII reg %02X", idx); 217 check_warn_goto_done(ret, "Timed out reading MII reg %02X", idx);
216 218
217 ret = smsc95xx_read_reg(dev, MII_DATA, &val); 219 ret = __smsc95xx_read_reg(dev, MII_DATA, &val, in_pm);
218 check_warn_goto_done(ret, "Error reading MII_DATA"); 220 check_warn_goto_done(ret, "Error reading MII_DATA");
219 221
220 ret = (u16)(val & 0xFFFF); 222 ret = (u16)(val & 0xFFFF);
@@ -224,8 +226,8 @@ done:
224 return ret; 226 return ret;
225} 227}
226 228
227static void smsc95xx_mdio_write(struct net_device *netdev, int phy_id, int idx, 229static void __smsc95xx_mdio_write(struct net_device *netdev, int phy_id,
228 int regval) 230 int idx, int regval, int in_pm)
229{ 231{
230 struct usbnet *dev = netdev_priv(netdev); 232 struct usbnet *dev = netdev_priv(netdev);
231 u32 val, addr; 233 u32 val, addr;
@@ -234,27 +236,50 @@ static void smsc95xx_mdio_write(struct net_device *netdev, int phy_id, int idx,
234 mutex_lock(&dev->phy_mutex); 236 mutex_lock(&dev->phy_mutex);
235 237
236 /* confirm MII not busy */ 238 /* confirm MII not busy */
237 ret = smsc95xx_phy_wait_not_busy(dev); 239 ret = __smsc95xx_phy_wait_not_busy(dev, in_pm);
238 check_warn_goto_done(ret, "MII is busy in smsc95xx_mdio_write"); 240 check_warn_goto_done(ret, "MII is busy in smsc95xx_mdio_write");
239 241
240 val = regval; 242 val = regval;
241 ret = smsc95xx_write_reg(dev, MII_DATA, val); 243 ret = __smsc95xx_write_reg(dev, MII_DATA, val, in_pm);
242 check_warn_goto_done(ret, "Error writing MII_DATA"); 244 check_warn_goto_done(ret, "Error writing MII_DATA");
243 245
244 /* set the address, index & direction (write to PHY) */ 246 /* set the address, index & direction (write to PHY) */
245 phy_id &= dev->mii.phy_id_mask; 247 phy_id &= dev->mii.phy_id_mask;
246 idx &= dev->mii.reg_num_mask; 248 idx &= dev->mii.reg_num_mask;
247 addr = (phy_id << 11) | (idx << 6) | MII_WRITE_ | MII_BUSY_; 249 addr = (phy_id << 11) | (idx << 6) | MII_WRITE_ | MII_BUSY_;
248 ret = smsc95xx_write_reg(dev, MII_ADDR, addr); 250 ret = __smsc95xx_write_reg(dev, MII_ADDR, addr, in_pm);
249 check_warn_goto_done(ret, "Error writing MII_ADDR"); 251 check_warn_goto_done(ret, "Error writing MII_ADDR");
250 252
251 ret = smsc95xx_phy_wait_not_busy(dev); 253 ret = __smsc95xx_phy_wait_not_busy(dev, in_pm);
252 check_warn_goto_done(ret, "Timed out writing MII reg %02X", idx); 254 check_warn_goto_done(ret, "Timed out writing MII reg %02X", idx);
253 255
254done: 256done:
255 mutex_unlock(&dev->phy_mutex); 257 mutex_unlock(&dev->phy_mutex);
256} 258}
257 259
260static int smsc95xx_mdio_read_nopm(struct net_device *netdev, int phy_id,
261 int idx)
262{
263 return __smsc95xx_mdio_read(netdev, phy_id, idx, 1);
264}
265
266static void smsc95xx_mdio_write_nopm(struct net_device *netdev, int phy_id,
267 int idx, int regval)
268{
269 __smsc95xx_mdio_write(netdev, phy_id, idx, regval, 1);
270}
271
272static int smsc95xx_mdio_read(struct net_device *netdev, int phy_id, int idx)
273{
274 return __smsc95xx_mdio_read(netdev, phy_id, idx, 0);
275}
276
277static void smsc95xx_mdio_write(struct net_device *netdev, int phy_id, int idx,
278 int regval)
279{
280 __smsc95xx_mdio_write(netdev, phy_id, idx, regval, 0);
281}
282
258static int __must_check smsc95xx_wait_eeprom(struct usbnet *dev) 283static int __must_check smsc95xx_wait_eeprom(struct usbnet *dev)
259{ 284{
260 unsigned long start_time = jiffies; 285 unsigned long start_time = jiffies;
@@ -1068,18 +1093,61 @@ static u16 smsc_crc(const u8 *buffer, size_t len, int filter)
1068 return bitrev16(crc16(0xFFFF, buffer, len)) << ((filter % 2) * 16); 1093 return bitrev16(crc16(0xFFFF, buffer, len)) << ((filter % 2) * 16);
1069} 1094}
1070 1095
1096static int smsc95xx_enable_phy_wakeup_interrupts(struct usbnet *dev, u16 mask)
1097{
1098 struct mii_if_info *mii = &dev->mii;
1099 int ret;
1100
1101 netdev_dbg(dev->net, "enabling PHY wakeup interrupts");
1102
1103 /* read to clear */
1104 ret = smsc95xx_mdio_read_nopm(dev->net, mii->phy_id, PHY_INT_SRC);
1105 check_warn_return(ret, "Error reading PHY_INT_SRC");
1106
1107 /* enable interrupt source */
1108 ret = smsc95xx_mdio_read_nopm(dev->net, mii->phy_id, PHY_INT_MASK);
1109 check_warn_return(ret, "Error reading PHY_INT_MASK");
1110
1111 ret |= mask;
1112
1113 smsc95xx_mdio_write_nopm(dev->net, mii->phy_id, PHY_INT_MASK, ret);
1114
1115 return 0;
1116}
1117
1118static int smsc95xx_link_ok_nopm(struct usbnet *dev)
1119{
1120 struct mii_if_info *mii = &dev->mii;
1121 int ret;
1122
1123 /* first, a dummy read, needed to latch some MII phys */
1124 ret = smsc95xx_mdio_read_nopm(dev->net, mii->phy_id, MII_BMSR);
1125 check_warn_return(ret, "Error reading MII_BMSR");
1126
1127 ret = smsc95xx_mdio_read_nopm(dev->net, mii->phy_id, MII_BMSR);
1128 check_warn_return(ret, "Error reading MII_BMSR");
1129
1130 return !!(ret & BMSR_LSTATUS);
1131}
1132
1071static int smsc95xx_suspend(struct usb_interface *intf, pm_message_t message) 1133static int smsc95xx_suspend(struct usb_interface *intf, pm_message_t message)
1072{ 1134{
1073 struct usbnet *dev = usb_get_intfdata(intf); 1135 struct usbnet *dev = usb_get_intfdata(intf);
1074 struct smsc95xx_priv *pdata = (struct smsc95xx_priv *)(dev->data[0]); 1136 struct smsc95xx_priv *pdata = (struct smsc95xx_priv *)(dev->data[0]);
1137 u32 val, link_up;
1075 int ret; 1138 int ret;
1076 u32 val;
1077 1139
1078 ret = usbnet_suspend(intf, message); 1140 ret = usbnet_suspend(intf, message);
1079 check_warn_return(ret, "usbnet_suspend error"); 1141 check_warn_return(ret, "usbnet_suspend error");
1080 1142
1081 /* if no wol options set, enter lowest power SUSPEND2 mode */ 1143 /* determine if link is up using only _nopm functions */
1082 if (!(pdata->wolopts & SUPPORTED_WAKE)) { 1144 link_up = smsc95xx_link_ok_nopm(dev);
1145
1146 /* if no wol options set, or if link is down and we're not waking on
1147 * PHY activity, enter lowest power SUSPEND2 mode
1148 */
1149 if (!(pdata->wolopts & SUPPORTED_WAKE) ||
1150 !(link_up || (pdata->wolopts & WAKE_PHY))) {
1083 netdev_info(dev->net, "entering SUSPEND2 mode"); 1151 netdev_info(dev->net, "entering SUSPEND2 mode");
1084 1152
1085 /* disable energy detect (link up) & wake up events */ 1153 /* disable energy detect (link up) & wake up events */
@@ -1112,6 +1180,59 @@ static int smsc95xx_suspend(struct usb_interface *intf, pm_message_t message)
1112 return 0; 1180 return 0;
1113 } 1181 }
1114 1182
1183 if (pdata->wolopts & WAKE_PHY) {
1184 ret = smsc95xx_enable_phy_wakeup_interrupts(dev,
1185 (PHY_INT_MASK_ANEG_COMP_ | PHY_INT_MASK_LINK_DOWN_));
1186 check_warn_return(ret, "error enabling PHY wakeup ints");
1187
1188 /* if link is down then configure EDPD and enter SUSPEND1,
1189 * otherwise enter SUSPEND0 below
1190 */
1191 if (!link_up) {
1192 struct mii_if_info *mii = &dev->mii;
1193 netdev_info(dev->net, "entering SUSPEND1 mode");
1194
1195 /* reconfigure link pulse detection timing for
1196 * compatibility with non-standard link partners
1197 */
1198 if (pdata->features & FEATURE_PHY_NLP_CROSSOVER)
1199 smsc95xx_mdio_write_nopm(dev->net, mii->phy_id,
1200 PHY_EDPD_CONFIG,
1201 PHY_EDPD_CONFIG_DEFAULT);
1202
1203 /* enable energy detect power-down mode */
1204 ret = smsc95xx_mdio_read_nopm(dev->net, mii->phy_id,
1205 PHY_MODE_CTRL_STS);
1206 check_warn_return(ret, "Error reading PHY_MODE_CTRL_STS");
1207
1208 ret |= MODE_CTRL_STS_EDPWRDOWN_;
1209
1210 smsc95xx_mdio_write_nopm(dev->net, mii->phy_id,
1211 PHY_MODE_CTRL_STS, ret);
1212
1213 /* enter SUSPEND1 mode */
1214 ret = smsc95xx_read_reg_nopm(dev, PM_CTRL, &val);
1215 check_warn_return(ret, "Error reading PM_CTRL");
1216
1217 val &= ~(PM_CTL_SUS_MODE_ | PM_CTL_WUPS_ | PM_CTL_PHY_RST_);
1218 val |= PM_CTL_SUS_MODE_1;
1219
1220 ret = smsc95xx_write_reg_nopm(dev, PM_CTRL, val);
1221 check_warn_return(ret, "Error writing PM_CTRL");
1222
1223 /* clear wol status, enable energy detection */
1224 val &= ~PM_CTL_WUPS_;
1225 val |= (PM_CTL_WUPS_ED_ | PM_CTL_ED_EN_);
1226
1227 ret = smsc95xx_write_reg_nopm(dev, PM_CTRL, val);
1228 check_warn_return(ret, "Error writing PM_CTRL");
1229
1230 smsc95xx_set_feature(dev, USB_DEVICE_REMOTE_WAKEUP);
1231
1232 return 0;
1233 }
1234 }
1235
1115 if (pdata->wolopts & (WAKE_BCAST | WAKE_MCAST | WAKE_ARP | WAKE_UCAST)) { 1236 if (pdata->wolopts & (WAKE_BCAST | WAKE_MCAST | WAKE_ARP | WAKE_UCAST)) {
1116 u32 *filter_mask = kzalloc(32, GFP_KERNEL); 1237 u32 *filter_mask = kzalloc(32, GFP_KERNEL);
1117 u32 command[2]; 1238 u32 command[2];
@@ -1250,6 +1371,10 @@ static int smsc95xx_suspend(struct usb_interface *intf, pm_message_t message)
1250 1371
1251 val |= PM_CTL_WOL_EN_; 1372 val |= PM_CTL_WOL_EN_;
1252 1373
1374 /* phy energy detect wakeup source */
1375 if (pdata->wolopts & WAKE_PHY)
1376 val |= PM_CTL_ED_EN_;
1377
1253 ret = smsc95xx_write_reg_nopm(dev, PM_CTRL, val); 1378 ret = smsc95xx_write_reg_nopm(dev, PM_CTRL, val);
1254 check_warn_return(ret, "Error writing PM_CTRL"); 1379 check_warn_return(ret, "Error writing PM_CTRL");
1255 1380
@@ -1271,6 +1396,11 @@ static int smsc95xx_suspend(struct usb_interface *intf, pm_message_t message)
1271 /* clear wol status */ 1396 /* clear wol status */
1272 val &= ~PM_CTL_WUPS_; 1397 val &= ~PM_CTL_WUPS_;
1273 val |= PM_CTL_WUPS_WOL_; 1398 val |= PM_CTL_WUPS_WOL_;
1399
1400 /* enable energy detection */
1401 if (pdata->wolopts & WAKE_PHY)
1402 val |= PM_CTL_WUPS_ED_;
1403
1274 ret = smsc95xx_write_reg_nopm(dev, PM_CTRL, val); 1404 ret = smsc95xx_write_reg_nopm(dev, PM_CTRL, val);
1275 check_warn_return(ret, "Error writing PM_CTRL"); 1405 check_warn_return(ret, "Error writing PM_CTRL");
1276 1406
diff --git a/drivers/net/usb/smsc95xx.h b/drivers/net/usb/smsc95xx.h
index 99f04a251a4e..f360ee372554 100644
--- a/drivers/net/usb/smsc95xx.h
+++ b/drivers/net/usb/smsc95xx.h
@@ -226,6 +226,23 @@
226 226
227/* Vendor-specific PHY Definitions */ 227/* Vendor-specific PHY Definitions */
228 228
229/* EDPD NLP / crossover time configuration (LAN9500A only) */
230#define PHY_EDPD_CONFIG (16)
231#define PHY_EDPD_CONFIG_TX_NLP_EN_ ((u16)0x8000)
232#define PHY_EDPD_CONFIG_TX_NLP_1000_ ((u16)0x0000)
233#define PHY_EDPD_CONFIG_TX_NLP_768_ ((u16)0x2000)
234#define PHY_EDPD_CONFIG_TX_NLP_512_ ((u16)0x4000)
235#define PHY_EDPD_CONFIG_TX_NLP_256_ ((u16)0x6000)
236#define PHY_EDPD_CONFIG_RX_1_NLP_ ((u16)0x1000)
237#define PHY_EDPD_CONFIG_RX_NLP_64_ ((u16)0x0000)
238#define PHY_EDPD_CONFIG_RX_NLP_256_ ((u16)0x0400)
239#define PHY_EDPD_CONFIG_RX_NLP_512_ ((u16)0x0800)
240#define PHY_EDPD_CONFIG_RX_NLP_1000_ ((u16)0x0C00)
241#define PHY_EDPD_CONFIG_EXT_CROSSOVER_ ((u16)0x0001)
242#define PHY_EDPD_CONFIG_DEFAULT (PHY_EDPD_CONFIG_TX_NLP_EN_ | \
243 PHY_EDPD_CONFIG_TX_NLP_768_ | \
244 PHY_EDPD_CONFIG_RX_1_NLP_)
245
229/* Mode Control/Status Register */ 246/* Mode Control/Status Register */
230#define PHY_MODE_CTRL_STS (17) 247#define PHY_MODE_CTRL_STS (17)
231#define MODE_CTRL_STS_EDPWRDOWN_ ((u16)0x2000) 248#define MODE_CTRL_STS_EDPWRDOWN_ ((u16)0x2000)