aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/usb/asix_common.c
diff options
context:
space:
mode:
authorRobert Foss <robert.foss@collabora.com>2016-08-29 09:32:15 -0400
committerDavid S. Miller <davem@davemloft.net>2016-09-01 00:07:05 -0400
commitd9fe64e511144c1ee7d7555b4111f09dde9692ef (patch)
tree2e69c80dc328131d744ae10b494c227c0a659079 /drivers/net/usb/asix_common.c
parentc7735f1bac209e285839ccead00873b27afc013b (diff)
net: asix: Add in_pm parameter
From: Freddy Xin <freddy@asix.com.tw> In order to R/W registers in suspend/resume functions, in_pm flags are added to some functions to determine whether the nopm version of usb functions is called. Save BMCR and ANAR PHY registers in suspend function and restore them in resume function. Reset HW in resume function to ensure the PHY works correctly. Signed-off-by: Freddy Xin <freddy@asix.com.tw> Signed-off-by: Robert Foss <robert.foss@collabora.com> Tested-by: Robert Foss <robert.foss@collabora.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/usb/asix_common.c')
-rw-r--r--drivers/net/usb/asix_common.c180
1 files changed, 137 insertions, 43 deletions
diff --git a/drivers/net/usb/asix_common.c b/drivers/net/usb/asix_common.c
index 7de5ab589e4e..25609eefc762 100644
--- a/drivers/net/usb/asix_common.c
+++ b/drivers/net/usb/asix_common.c
@@ -22,24 +22,49 @@
22#include "asix.h" 22#include "asix.h"
23 23
24int asix_read_cmd(struct usbnet *dev, u8 cmd, u16 value, u16 index, 24int asix_read_cmd(struct usbnet *dev, u8 cmd, u16 value, u16 index,
25 u16 size, void *data) 25 u16 size, void *data, int in_pm)
26{ 26{
27 int ret; 27 int ret;
28 ret = usbnet_read_cmd(dev, cmd, 28 int (*fn)(struct usbnet *, u8, u8, u16, u16, void *, u16);
29 USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, 29
30 value, index, data, size); 30 BUG_ON(!dev);
31
32 if (!in_pm)
33 fn = usbnet_read_cmd;
34 else
35 fn = usbnet_read_cmd_nopm;
36
37 ret = fn(dev, cmd, USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
38 value, index, data, size);
39
40 if (unlikely(ret < 0))
41 netdev_warn(dev->net, "Failed to read reg index 0x%04x: %d\n",
42 index, ret);
31 43
32 if (ret != size && ret >= 0)
33 return -EINVAL;
34 return ret; 44 return ret;
35} 45}
36 46
37int asix_write_cmd(struct usbnet *dev, u8 cmd, u16 value, u16 index, 47int asix_write_cmd(struct usbnet *dev, u8 cmd, u16 value, u16 index,
38 u16 size, void *data) 48 u16 size, void *data, int in_pm)
39{ 49{
40 return usbnet_write_cmd(dev, cmd, 50 int ret;
41 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, 51 int (*fn)(struct usbnet *, u8, u8, u16, u16, const void *, u16);
42 value, index, data, size); 52
53 BUG_ON(!dev);
54
55 if (!in_pm)
56 fn = usbnet_write_cmd;
57 else
58 fn = usbnet_write_cmd_nopm;
59
60 ret = fn(dev, cmd, USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
61 value, index, data, size);
62
63 if (unlikely(ret < 0))
64 netdev_warn(dev->net, "Failed to write reg index 0x%04x: %d\n",
65 index, ret);
66
67 return ret;
43} 68}
44 69
45void asix_write_cmd_async(struct usbnet *dev, u8 cmd, u16 value, u16 index, 70void asix_write_cmd_async(struct usbnet *dev, u8 cmd, u16 value, u16 index,
@@ -225,19 +250,20 @@ struct sk_buff *asix_tx_fixup(struct usbnet *dev, struct sk_buff *skb,
225 return skb; 250 return skb;
226} 251}
227 252
228int asix_set_sw_mii(struct usbnet *dev) 253int asix_set_sw_mii(struct usbnet *dev, int in_pm)
229{ 254{
230 int ret; 255 int ret;
231 ret = asix_write_cmd(dev, AX_CMD_SET_SW_MII, 0x0000, 0, 0, NULL); 256 ret = asix_write_cmd(dev, AX_CMD_SET_SW_MII, 0x0000, 0, 0, NULL, in_pm);
257
232 if (ret < 0) 258 if (ret < 0)
233 netdev_err(dev->net, "Failed to enable software MII access\n"); 259 netdev_err(dev->net, "Failed to enable software MII access\n");
234 return ret; 260 return ret;
235} 261}
236 262
237int asix_set_hw_mii(struct usbnet *dev) 263int asix_set_hw_mii(struct usbnet *dev, int in_pm)
238{ 264{
239 int ret; 265 int ret;
240 ret = asix_write_cmd(dev, AX_CMD_SET_HW_MII, 0x0000, 0, 0, NULL); 266 ret = asix_write_cmd(dev, AX_CMD_SET_HW_MII, 0x0000, 0, 0, NULL, in_pm);
241 if (ret < 0) 267 if (ret < 0)
242 netdev_err(dev->net, "Failed to enable hardware MII access\n"); 268 netdev_err(dev->net, "Failed to enable hardware MII access\n");
243 return ret; 269 return ret;
@@ -247,7 +273,7 @@ int asix_read_phy_addr(struct usbnet *dev, int internal)
247{ 273{
248 int offset = (internal ? 1 : 0); 274 int offset = (internal ? 1 : 0);
249 u8 buf[2]; 275 u8 buf[2];
250 int ret = asix_read_cmd(dev, AX_CMD_READ_PHY_ID, 0, 0, 2, buf); 276 int ret = asix_read_cmd(dev, AX_CMD_READ_PHY_ID, 0, 0, 2, buf, 0);
251 277
252 netdev_dbg(dev->net, "asix_get_phy_addr()\n"); 278 netdev_dbg(dev->net, "asix_get_phy_addr()\n");
253 279
@@ -270,21 +296,21 @@ int asix_get_phy_addr(struct usbnet *dev)
270} 296}
271 297
272 298
273int asix_sw_reset(struct usbnet *dev, u8 flags) 299int asix_sw_reset(struct usbnet *dev, u8 flags, int in_pm)
274{ 300{
275 int ret; 301 int ret;
276 302
277 ret = asix_write_cmd(dev, AX_CMD_SW_RESET, flags, 0, 0, NULL); 303 ret = asix_write_cmd(dev, AX_CMD_SW_RESET, flags, 0, 0, NULL, in_pm);
278 if (ret < 0) 304 if (ret < 0)
279 netdev_err(dev->net, "Failed to send software reset: %02x\n", ret); 305 netdev_err(dev->net, "Failed to send software reset: %02x\n", ret);
280 306
281 return ret; 307 return ret;
282} 308}
283 309
284u16 asix_read_rx_ctl(struct usbnet *dev) 310u16 asix_read_rx_ctl(struct usbnet *dev, int in_pm)
285{ 311{
286 __le16 v; 312 __le16 v;
287 int ret = asix_read_cmd(dev, AX_CMD_READ_RX_CTL, 0, 0, 2, &v); 313 int ret = asix_read_cmd(dev, AX_CMD_READ_RX_CTL, 0, 0, 2, &v, in_pm);
288 314
289 if (ret < 0) { 315 if (ret < 0) {
290 netdev_err(dev->net, "Error reading RX_CTL register: %02x\n", ret); 316 netdev_err(dev->net, "Error reading RX_CTL register: %02x\n", ret);
@@ -295,12 +321,12 @@ out:
295 return ret; 321 return ret;
296} 322}
297 323
298int asix_write_rx_ctl(struct usbnet *dev, u16 mode) 324int asix_write_rx_ctl(struct usbnet *dev, u16 mode, int in_pm)
299{ 325{
300 int ret; 326 int ret;
301 327
302 netdev_dbg(dev->net, "asix_write_rx_ctl() - mode = 0x%04x\n", mode); 328 netdev_dbg(dev->net, "asix_write_rx_ctl() - mode = 0x%04x\n", mode);
303 ret = asix_write_cmd(dev, AX_CMD_WRITE_RX_CTL, mode, 0, 0, NULL); 329 ret = asix_write_cmd(dev, AX_CMD_WRITE_RX_CTL, mode, 0, 0, NULL, in_pm);
304 if (ret < 0) 330 if (ret < 0)
305 netdev_err(dev->net, "Failed to write RX_CTL mode to 0x%04x: %02x\n", 331 netdev_err(dev->net, "Failed to write RX_CTL mode to 0x%04x: %02x\n",
306 mode, ret); 332 mode, ret);
@@ -308,10 +334,11 @@ int asix_write_rx_ctl(struct usbnet *dev, u16 mode)
308 return ret; 334 return ret;
309} 335}
310 336
311u16 asix_read_medium_status(struct usbnet *dev) 337u16 asix_read_medium_status(struct usbnet *dev, int in_pm)
312{ 338{
313 __le16 v; 339 __le16 v;
314 int ret = asix_read_cmd(dev, AX_CMD_READ_MEDIUM_STATUS, 0, 0, 2, &v); 340 int ret = asix_read_cmd(dev, AX_CMD_READ_MEDIUM_STATUS,
341 0, 0, 2, &v, in_pm);
315 342
316 if (ret < 0) { 343 if (ret < 0) {
317 netdev_err(dev->net, "Error reading Medium Status register: %02x\n", 344 netdev_err(dev->net, "Error reading Medium Status register: %02x\n",
@@ -323,12 +350,13 @@ u16 asix_read_medium_status(struct usbnet *dev)
323 350
324} 351}
325 352
326int asix_write_medium_mode(struct usbnet *dev, u16 mode) 353int asix_write_medium_mode(struct usbnet *dev, u16 mode, int in_pm)
327{ 354{
328 int ret; 355 int ret;
329 356
330 netdev_dbg(dev->net, "asix_write_medium_mode() - mode = 0x%04x\n", mode); 357 netdev_dbg(dev->net, "asix_write_medium_mode() - mode = 0x%04x\n", mode);
331 ret = asix_write_cmd(dev, AX_CMD_WRITE_MEDIUM_MODE, mode, 0, 0, NULL); 358 ret = asix_write_cmd(dev, AX_CMD_WRITE_MEDIUM_MODE,
359 mode, 0, 0, NULL, in_pm);
332 if (ret < 0) 360 if (ret < 0)
333 netdev_err(dev->net, "Failed to write Medium Mode mode to 0x%04x: %02x\n", 361 netdev_err(dev->net, "Failed to write Medium Mode mode to 0x%04x: %02x\n",
334 mode, ret); 362 mode, ret);
@@ -336,12 +364,12 @@ int asix_write_medium_mode(struct usbnet *dev, u16 mode)
336 return ret; 364 return ret;
337} 365}
338 366
339int asix_write_gpio(struct usbnet *dev, u16 value, int sleep) 367int asix_write_gpio(struct usbnet *dev, u16 value, int sleep, int in_pm)
340{ 368{
341 int ret; 369 int ret;
342 370
343 netdev_dbg(dev->net, "asix_write_gpio() - value = 0x%04x\n", value); 371 netdev_dbg(dev->net, "asix_write_gpio() - value = 0x%04x\n", value);
344 ret = asix_write_cmd(dev, AX_CMD_WRITE_GPIOS, value, 0, 0, NULL); 372 ret = asix_write_cmd(dev, AX_CMD_WRITE_GPIOS, value, 0, 0, NULL, in_pm);
345 if (ret < 0) 373 if (ret < 0)
346 netdev_err(dev->net, "Failed to write GPIO value 0x%04x: %02x\n", 374 netdev_err(dev->net, "Failed to write GPIO value 0x%04x: %02x\n",
347 value, ret); 375 value, ret);
@@ -398,16 +426,23 @@ int asix_mdio_read(struct net_device *netdev, int phy_id, int loc)
398{ 426{
399 struct usbnet *dev = netdev_priv(netdev); 427 struct usbnet *dev = netdev_priv(netdev);
400 __le16 res; 428 __le16 res;
429 u8 smsr;
430 int i = 0;
401 431
402 mutex_lock(&dev->phy_mutex); 432 mutex_lock(&dev->phy_mutex);
403 asix_set_sw_mii(dev); 433 do {
434 asix_set_sw_mii(dev, 0);
435 usleep_range(1000, 1100);
436 asix_read_cmd(dev, AX_CMD_STATMNGSTS_REG, 0, 0, 1, &smsr, 0);
437 } while (!(smsr & AX_HOST_EN) && (i++ < 30));
438
404 asix_read_cmd(dev, AX_CMD_READ_MII_REG, phy_id, 439 asix_read_cmd(dev, AX_CMD_READ_MII_REG, phy_id,
405 (__u16)loc, 2, &res); 440 (__u16)loc, 2, &res, 0);
406 asix_set_hw_mii(dev); 441 asix_set_hw_mii(dev, 0);
407 mutex_unlock(&dev->phy_mutex); 442 mutex_unlock(&dev->phy_mutex);
408 443
409 netdev_dbg(dev->net, "asix_mdio_read() phy_id=0x%02x, loc=0x%02x, returns=0x%04x\n", 444 netdev_dbg(dev->net, "asix_mdio_read() phy_id=0x%02x, loc=0x%02x, returns=0x%04x\n",
410 phy_id, loc, le16_to_cpu(res)); 445 phy_id, loc, le16_to_cpu(res));
411 446
412 return le16_to_cpu(res); 447 return le16_to_cpu(res);
413} 448}
@@ -416,13 +451,71 @@ void asix_mdio_write(struct net_device *netdev, int phy_id, int loc, int val)
416{ 451{
417 struct usbnet *dev = netdev_priv(netdev); 452 struct usbnet *dev = netdev_priv(netdev);
418 __le16 res = cpu_to_le16(val); 453 __le16 res = cpu_to_le16(val);
454 u8 smsr;
455 int i = 0;
419 456
420 netdev_dbg(dev->net, "asix_mdio_write() phy_id=0x%02x, loc=0x%02x, val=0x%04x\n", 457 netdev_dbg(dev->net, "asix_mdio_write() phy_id=0x%02x, loc=0x%02x, val=0x%04x\n",
421 phy_id, loc, val); 458 phy_id, loc, val);
459
460 mutex_lock(&dev->phy_mutex);
461 do {
462 asix_set_sw_mii(dev, 0);
463 usleep_range(1000, 1100);
464 asix_read_cmd(dev, AX_CMD_STATMNGSTS_REG, 0, 0, 1, &smsr, 0);
465 } while (!(smsr & AX_HOST_EN) && (i++ < 30));
466
467 asix_write_cmd(dev, AX_CMD_WRITE_MII_REG, phy_id,
468 (__u16)loc, 2, &res, 0);
469 asix_set_hw_mii(dev, 0);
470 mutex_unlock(&dev->phy_mutex);
471}
472
473int asix_mdio_read_nopm(struct net_device *netdev, int phy_id, int loc)
474{
475 struct usbnet *dev = netdev_priv(netdev);
476 __le16 res;
477 u8 smsr;
478 int i = 0;
479
480 mutex_lock(&dev->phy_mutex);
481 do {
482 asix_set_sw_mii(dev, 1);
483 usleep_range(1000, 1100);
484 asix_read_cmd(dev, AX_CMD_STATMNGSTS_REG, 0, 0, 1, &smsr, 1);
485 } while (!(smsr & AX_HOST_EN) && (i++ < 30));
486
487 asix_read_cmd(dev, AX_CMD_READ_MII_REG, phy_id,
488 (__u16)loc, 2, &res, 1);
489 asix_set_hw_mii(dev, 1);
490 mutex_unlock(&dev->phy_mutex);
491
492 netdev_dbg(dev->net, "asix_mdio_read_nopm() phy_id=0x%02x, loc=0x%02x, returns=0x%04x\n",
493 phy_id, loc, le16_to_cpu(res));
494
495 return le16_to_cpu(res);
496}
497
498void
499asix_mdio_write_nopm(struct net_device *netdev, int phy_id, int loc, int val)
500{
501 struct usbnet *dev = netdev_priv(netdev);
502 __le16 res = cpu_to_le16(val);
503 u8 smsr;
504 int i = 0;
505
506 netdev_dbg(dev->net, "asix_mdio_write() phy_id=0x%02x, loc=0x%02x, val=0x%04x\n",
507 phy_id, loc, val);
508
422 mutex_lock(&dev->phy_mutex); 509 mutex_lock(&dev->phy_mutex);
423 asix_set_sw_mii(dev); 510 do {
424 asix_write_cmd(dev, AX_CMD_WRITE_MII_REG, phy_id, (__u16)loc, 2, &res); 511 asix_set_sw_mii(dev, 1);
425 asix_set_hw_mii(dev); 512 usleep_range(1000, 1100);
513 asix_read_cmd(dev, AX_CMD_STATMNGSTS_REG, 0, 0, 1, &smsr, 1);
514 } while (!(smsr & AX_HOST_EN) && (i++ < 30));
515
516 asix_write_cmd(dev, AX_CMD_WRITE_MII_REG, phy_id,
517 (__u16)loc, 2, &res, 1);
518 asix_set_hw_mii(dev, 1);
426 mutex_unlock(&dev->phy_mutex); 519 mutex_unlock(&dev->phy_mutex);
427} 520}
428 521
@@ -431,7 +524,8 @@ void asix_get_wol(struct net_device *net, struct ethtool_wolinfo *wolinfo)
431 struct usbnet *dev = netdev_priv(net); 524 struct usbnet *dev = netdev_priv(net);
432 u8 opt; 525 u8 opt;
433 526
434 if (asix_read_cmd(dev, AX_CMD_READ_MONITOR_MODE, 0, 0, 1, &opt) < 0) { 527 if (asix_read_cmd(dev, AX_CMD_READ_MONITOR_MODE,
528 0, 0, 1, &opt, 0) < 0) {
435 wolinfo->supported = 0; 529 wolinfo->supported = 0;
436 wolinfo->wolopts = 0; 530 wolinfo->wolopts = 0;
437 return; 531 return;
@@ -455,7 +549,7 @@ int asix_set_wol(struct net_device *net, struct ethtool_wolinfo *wolinfo)
455 opt |= AX_MONITOR_MAGIC; 549 opt |= AX_MONITOR_MAGIC;
456 550
457 if (asix_write_cmd(dev, AX_CMD_WRITE_MONITOR_MODE, 551 if (asix_write_cmd(dev, AX_CMD_WRITE_MONITOR_MODE,
458 opt, 0, 0, NULL) < 0) 552 opt, 0, 0, NULL, 0) < 0)
459 return -EINVAL; 553 return -EINVAL;
460 554
461 return 0; 555 return 0;
@@ -490,7 +584,7 @@ int asix_get_eeprom(struct net_device *net, struct ethtool_eeprom *eeprom,
490 /* ax8817x returns 2 bytes from eeprom on read */ 584 /* ax8817x returns 2 bytes from eeprom on read */
491 for (i = first_word; i <= last_word; i++) { 585 for (i = first_word; i <= last_word; i++) {
492 if (asix_read_cmd(dev, AX_CMD_READ_EEPROM, i, 0, 2, 586 if (asix_read_cmd(dev, AX_CMD_READ_EEPROM, i, 0, 2,
493 &(eeprom_buff[i - first_word])) < 0) { 587 &eeprom_buff[i - first_word], 0) < 0) {
494 kfree(eeprom_buff); 588 kfree(eeprom_buff);
495 return -EIO; 589 return -EIO;
496 } 590 }
@@ -531,7 +625,7 @@ int asix_set_eeprom(struct net_device *net, struct ethtool_eeprom *eeprom,
531 the EEPROM */ 625 the EEPROM */
532 if (eeprom->offset & 1) { 626 if (eeprom->offset & 1) {
533 ret = asix_read_cmd(dev, AX_CMD_READ_EEPROM, first_word, 0, 2, 627 ret = asix_read_cmd(dev, AX_CMD_READ_EEPROM, first_word, 0, 2,
534 &(eeprom_buff[0])); 628 &eeprom_buff[0], 0);
535 if (ret < 0) { 629 if (ret < 0) {
536 netdev_err(net, "Failed to read EEPROM at offset 0x%02x.\n", first_word); 630 netdev_err(net, "Failed to read EEPROM at offset 0x%02x.\n", first_word);
537 goto free; 631 goto free;
@@ -540,7 +634,7 @@ int asix_set_eeprom(struct net_device *net, struct ethtool_eeprom *eeprom,
540 634
541 if ((eeprom->offset + eeprom->len) & 1) { 635 if ((eeprom->offset + eeprom->len) & 1) {
542 ret = asix_read_cmd(dev, AX_CMD_READ_EEPROM, last_word, 0, 2, 636 ret = asix_read_cmd(dev, AX_CMD_READ_EEPROM, last_word, 0, 2,
543 &(eeprom_buff[last_word - first_word])); 637 &eeprom_buff[last_word - first_word], 0);
544 if (ret < 0) { 638 if (ret < 0) {
545 netdev_err(net, "Failed to read EEPROM at offset 0x%02x.\n", last_word); 639 netdev_err(net, "Failed to read EEPROM at offset 0x%02x.\n", last_word);
546 goto free; 640 goto free;
@@ -550,7 +644,7 @@ int asix_set_eeprom(struct net_device *net, struct ethtool_eeprom *eeprom,
550 memcpy((u8 *)eeprom_buff + (eeprom->offset & 1), data, eeprom->len); 644 memcpy((u8 *)eeprom_buff + (eeprom->offset & 1), data, eeprom->len);
551 645
552 /* write data to EEPROM */ 646 /* write data to EEPROM */
553 ret = asix_write_cmd(dev, AX_CMD_WRITE_ENABLE, 0x0000, 0, 0, NULL); 647 ret = asix_write_cmd(dev, AX_CMD_WRITE_ENABLE, 0x0000, 0, 0, NULL, 0);
554 if (ret < 0) { 648 if (ret < 0) {
555 netdev_err(net, "Failed to enable EEPROM write\n"); 649 netdev_err(net, "Failed to enable EEPROM write\n");
556 goto free; 650 goto free;
@@ -561,7 +655,7 @@ int asix_set_eeprom(struct net_device *net, struct ethtool_eeprom *eeprom,
561 netdev_dbg(net, "write to EEPROM at offset 0x%02x, data 0x%04x\n", 655 netdev_dbg(net, "write to EEPROM at offset 0x%02x, data 0x%04x\n",
562 i, eeprom_buff[i - first_word]); 656 i, eeprom_buff[i - first_word]);
563 ret = asix_write_cmd(dev, AX_CMD_WRITE_EEPROM, i, 657 ret = asix_write_cmd(dev, AX_CMD_WRITE_EEPROM, i,
564 eeprom_buff[i - first_word], 0, NULL); 658 eeprom_buff[i - first_word], 0, NULL, 0);
565 if (ret < 0) { 659 if (ret < 0) {
566 netdev_err(net, "Failed to write EEPROM at offset 0x%02x.\n", 660 netdev_err(net, "Failed to write EEPROM at offset 0x%02x.\n",
567 i); 661 i);
@@ -570,7 +664,7 @@ int asix_set_eeprom(struct net_device *net, struct ethtool_eeprom *eeprom,
570 msleep(20); 664 msleep(20);
571 } 665 }
572 666
573 ret = asix_write_cmd(dev, AX_CMD_WRITE_DISABLE, 0x0000, 0, 0, NULL); 667 ret = asix_write_cmd(dev, AX_CMD_WRITE_DISABLE, 0x0000, 0, 0, NULL, 0);
574 if (ret < 0) { 668 if (ret < 0) {
575 netdev_err(net, "Failed to disable EEPROM write\n"); 669 netdev_err(net, "Failed to disable EEPROM write\n");
576 goto free; 670 goto free;