diff options
Diffstat (limited to 'drivers/net/usb/lan78xx.c')
-rw-r--r-- | drivers/net/usb/lan78xx.c | 132 |
1 files changed, 88 insertions, 44 deletions
diff --git a/drivers/net/usb/lan78xx.c b/drivers/net/usb/lan78xx.c index 2ed53331bfb2..1c299b8a162d 100644 --- a/drivers/net/usb/lan78xx.c +++ b/drivers/net/usb/lan78xx.c | |||
@@ -36,7 +36,7 @@ | |||
36 | #define DRIVER_AUTHOR "WOOJUNG HUH <woojung.huh@microchip.com>" | 36 | #define DRIVER_AUTHOR "WOOJUNG HUH <woojung.huh@microchip.com>" |
37 | #define DRIVER_DESC "LAN78XX USB 3.0 Gigabit Ethernet Devices" | 37 | #define DRIVER_DESC "LAN78XX USB 3.0 Gigabit Ethernet Devices" |
38 | #define DRIVER_NAME "lan78xx" | 38 | #define DRIVER_NAME "lan78xx" |
39 | #define DRIVER_VERSION "1.0.1" | 39 | #define DRIVER_VERSION "1.0.2" |
40 | 40 | ||
41 | #define TX_TIMEOUT_JIFFIES (5 * HZ) | 41 | #define TX_TIMEOUT_JIFFIES (5 * HZ) |
42 | #define THROTTLE_JIFFIES (HZ / 8) | 42 | #define THROTTLE_JIFFIES (HZ / 8) |
@@ -462,32 +462,53 @@ static int lan78xx_read_raw_eeprom(struct lan78xx_net *dev, u32 offset, | |||
462 | u32 length, u8 *data) | 462 | u32 length, u8 *data) |
463 | { | 463 | { |
464 | u32 val; | 464 | u32 val; |
465 | u32 saved; | ||
465 | int i, ret; | 466 | int i, ret; |
467 | int retval; | ||
466 | 468 | ||
467 | ret = lan78xx_eeprom_confirm_not_busy(dev); | 469 | /* depends on chip, some EEPROM pins are muxed with LED function. |
468 | if (ret) | 470 | * disable & restore LED function to access EEPROM. |
469 | return ret; | 471 | */ |
472 | ret = lan78xx_read_reg(dev, HW_CFG, &val); | ||
473 | saved = val; | ||
474 | if ((dev->devid & ID_REV_CHIP_ID_MASK_) == 0x78000000) { | ||
475 | val &= ~(HW_CFG_LED1_EN_ | HW_CFG_LED0_EN_); | ||
476 | ret = lan78xx_write_reg(dev, HW_CFG, val); | ||
477 | } | ||
478 | |||
479 | retval = lan78xx_eeprom_confirm_not_busy(dev); | ||
480 | if (retval) | ||
481 | return retval; | ||
470 | 482 | ||
471 | for (i = 0; i < length; i++) { | 483 | for (i = 0; i < length; i++) { |
472 | val = E2P_CMD_EPC_BUSY_ | E2P_CMD_EPC_CMD_READ_; | 484 | val = E2P_CMD_EPC_BUSY_ | E2P_CMD_EPC_CMD_READ_; |
473 | val |= (offset & E2P_CMD_EPC_ADDR_MASK_); | 485 | val |= (offset & E2P_CMD_EPC_ADDR_MASK_); |
474 | ret = lan78xx_write_reg(dev, E2P_CMD, val); | 486 | ret = lan78xx_write_reg(dev, E2P_CMD, val); |
475 | if (unlikely(ret < 0)) | 487 | if (unlikely(ret < 0)) { |
476 | return -EIO; | 488 | retval = -EIO; |
489 | goto exit; | ||
490 | } | ||
477 | 491 | ||
478 | ret = lan78xx_wait_eeprom(dev); | 492 | retval = lan78xx_wait_eeprom(dev); |
479 | if (ret < 0) | 493 | if (retval < 0) |
480 | return ret; | 494 | goto exit; |
481 | 495 | ||
482 | ret = lan78xx_read_reg(dev, E2P_DATA, &val); | 496 | ret = lan78xx_read_reg(dev, E2P_DATA, &val); |
483 | if (unlikely(ret < 0)) | 497 | if (unlikely(ret < 0)) { |
484 | return -EIO; | 498 | retval = -EIO; |
499 | goto exit; | ||
500 | } | ||
485 | 501 | ||
486 | data[i] = val & 0xFF; | 502 | data[i] = val & 0xFF; |
487 | offset++; | 503 | offset++; |
488 | } | 504 | } |
489 | 505 | ||
490 | return 0; | 506 | retval = 0; |
507 | exit: | ||
508 | if ((dev->devid & ID_REV_CHIP_ID_MASK_) == 0x78000000) | ||
509 | ret = lan78xx_write_reg(dev, HW_CFG, saved); | ||
510 | |||
511 | return retval; | ||
491 | } | 512 | } |
492 | 513 | ||
493 | static int lan78xx_read_eeprom(struct lan78xx_net *dev, u32 offset, | 514 | static int lan78xx_read_eeprom(struct lan78xx_net *dev, u32 offset, |
@@ -509,44 +530,67 @@ static int lan78xx_write_raw_eeprom(struct lan78xx_net *dev, u32 offset, | |||
509 | u32 length, u8 *data) | 530 | u32 length, u8 *data) |
510 | { | 531 | { |
511 | u32 val; | 532 | u32 val; |
533 | u32 saved; | ||
512 | int i, ret; | 534 | int i, ret; |
535 | int retval; | ||
513 | 536 | ||
514 | ret = lan78xx_eeprom_confirm_not_busy(dev); | 537 | /* depends on chip, some EEPROM pins are muxed with LED function. |
515 | if (ret) | 538 | * disable & restore LED function to access EEPROM. |
516 | return ret; | 539 | */ |
540 | ret = lan78xx_read_reg(dev, HW_CFG, &val); | ||
541 | saved = val; | ||
542 | if ((dev->devid & ID_REV_CHIP_ID_MASK_) == 0x78000000) { | ||
543 | val &= ~(HW_CFG_LED1_EN_ | HW_CFG_LED0_EN_); | ||
544 | ret = lan78xx_write_reg(dev, HW_CFG, val); | ||
545 | } | ||
546 | |||
547 | retval = lan78xx_eeprom_confirm_not_busy(dev); | ||
548 | if (retval) | ||
549 | goto exit; | ||
517 | 550 | ||
518 | /* Issue write/erase enable command */ | 551 | /* Issue write/erase enable command */ |
519 | val = E2P_CMD_EPC_BUSY_ | E2P_CMD_EPC_CMD_EWEN_; | 552 | val = E2P_CMD_EPC_BUSY_ | E2P_CMD_EPC_CMD_EWEN_; |
520 | ret = lan78xx_write_reg(dev, E2P_CMD, val); | 553 | ret = lan78xx_write_reg(dev, E2P_CMD, val); |
521 | if (unlikely(ret < 0)) | 554 | if (unlikely(ret < 0)) { |
522 | return -EIO; | 555 | retval = -EIO; |
556 | goto exit; | ||
557 | } | ||
523 | 558 | ||
524 | ret = lan78xx_wait_eeprom(dev); | 559 | retval = lan78xx_wait_eeprom(dev); |
525 | if (ret < 0) | 560 | if (retval < 0) |
526 | return ret; | 561 | goto exit; |
527 | 562 | ||
528 | for (i = 0; i < length; i++) { | 563 | for (i = 0; i < length; i++) { |
529 | /* Fill data register */ | 564 | /* Fill data register */ |
530 | val = data[i]; | 565 | val = data[i]; |
531 | ret = lan78xx_write_reg(dev, E2P_DATA, val); | 566 | ret = lan78xx_write_reg(dev, E2P_DATA, val); |
532 | if (ret < 0) | 567 | if (ret < 0) { |
533 | return ret; | 568 | retval = -EIO; |
569 | goto exit; | ||
570 | } | ||
534 | 571 | ||
535 | /* Send "write" command */ | 572 | /* Send "write" command */ |
536 | val = E2P_CMD_EPC_BUSY_ | E2P_CMD_EPC_CMD_WRITE_; | 573 | val = E2P_CMD_EPC_BUSY_ | E2P_CMD_EPC_CMD_WRITE_; |
537 | val |= (offset & E2P_CMD_EPC_ADDR_MASK_); | 574 | val |= (offset & E2P_CMD_EPC_ADDR_MASK_); |
538 | ret = lan78xx_write_reg(dev, E2P_CMD, val); | 575 | ret = lan78xx_write_reg(dev, E2P_CMD, val); |
539 | if (ret < 0) | 576 | if (ret < 0) { |
540 | return ret; | 577 | retval = -EIO; |
578 | goto exit; | ||
579 | } | ||
541 | 580 | ||
542 | ret = lan78xx_wait_eeprom(dev); | 581 | retval = lan78xx_wait_eeprom(dev); |
543 | if (ret < 0) | 582 | if (retval < 0) |
544 | return ret; | 583 | goto exit; |
545 | 584 | ||
546 | offset++; | 585 | offset++; |
547 | } | 586 | } |
548 | 587 | ||
549 | return 0; | 588 | retval = 0; |
589 | exit: | ||
590 | if ((dev->devid & ID_REV_CHIP_ID_MASK_) == 0x78000000) | ||
591 | ret = lan78xx_write_reg(dev, HW_CFG, saved); | ||
592 | |||
593 | return retval; | ||
550 | } | 594 | } |
551 | 595 | ||
552 | static int lan78xx_read_raw_otp(struct lan78xx_net *dev, u32 offset, | 596 | static int lan78xx_read_raw_otp(struct lan78xx_net *dev, u32 offset, |
@@ -904,7 +948,6 @@ static int lan78xx_link_reset(struct lan78xx_net *dev) | |||
904 | 948 | ||
905 | if (!phydev->link && dev->link_on) { | 949 | if (!phydev->link && dev->link_on) { |
906 | dev->link_on = false; | 950 | dev->link_on = false; |
907 | netif_carrier_off(dev->net); | ||
908 | 951 | ||
909 | /* reset MAC */ | 952 | /* reset MAC */ |
910 | ret = lan78xx_read_reg(dev, MAC_CR, &buf); | 953 | ret = lan78xx_read_reg(dev, MAC_CR, &buf); |
@@ -914,6 +957,8 @@ static int lan78xx_link_reset(struct lan78xx_net *dev) | |||
914 | ret = lan78xx_write_reg(dev, MAC_CR, buf); | 957 | ret = lan78xx_write_reg(dev, MAC_CR, buf); |
915 | if (unlikely(ret < 0)) | 958 | if (unlikely(ret < 0)) |
916 | return -EIO; | 959 | return -EIO; |
960 | |||
961 | phy_mac_interrupt(phydev, 0); | ||
917 | } else if (phydev->link && !dev->link_on) { | 962 | } else if (phydev->link && !dev->link_on) { |
918 | dev->link_on = true; | 963 | dev->link_on = true; |
919 | 964 | ||
@@ -953,7 +998,7 @@ static int lan78xx_link_reset(struct lan78xx_net *dev) | |||
953 | ethtool_cmd_speed(&ecmd), ecmd.duplex, ladv, radv); | 998 | ethtool_cmd_speed(&ecmd), ecmd.duplex, ladv, radv); |
954 | 999 | ||
955 | ret = lan78xx_update_flowcontrol(dev, ecmd.duplex, ladv, radv); | 1000 | ret = lan78xx_update_flowcontrol(dev, ecmd.duplex, ladv, radv); |
956 | netif_carrier_on(dev->net); | 1001 | phy_mac_interrupt(phydev, 1); |
957 | } | 1002 | } |
958 | 1003 | ||
959 | return ret; | 1004 | return ret; |
@@ -1495,7 +1540,6 @@ done: | |||
1495 | static int lan78xx_mdio_init(struct lan78xx_net *dev) | 1540 | static int lan78xx_mdio_init(struct lan78xx_net *dev) |
1496 | { | 1541 | { |
1497 | int ret; | 1542 | int ret; |
1498 | int i; | ||
1499 | 1543 | ||
1500 | dev->mdiobus = mdiobus_alloc(); | 1544 | dev->mdiobus = mdiobus_alloc(); |
1501 | if (!dev->mdiobus) { | 1545 | if (!dev->mdiobus) { |
@@ -1511,10 +1555,6 @@ static int lan78xx_mdio_init(struct lan78xx_net *dev) | |||
1511 | snprintf(dev->mdiobus->id, MII_BUS_ID_SIZE, "usb-%03d:%03d", | 1555 | snprintf(dev->mdiobus->id, MII_BUS_ID_SIZE, "usb-%03d:%03d", |
1512 | dev->udev->bus->busnum, dev->udev->devnum); | 1556 | dev->udev->bus->busnum, dev->udev->devnum); |
1513 | 1557 | ||
1514 | /* handle our own interrupt */ | ||
1515 | for (i = 0; i < PHY_MAX_ADDR; i++) | ||
1516 | dev->mdiobus->irq[i] = PHY_IGNORE_INTERRUPT; | ||
1517 | |||
1518 | switch (dev->devid & ID_REV_CHIP_ID_MASK_) { | 1558 | switch (dev->devid & ID_REV_CHIP_ID_MASK_) { |
1519 | case 0x78000000: | 1559 | case 0x78000000: |
1520 | case 0x78500000: | 1560 | case 0x78500000: |
@@ -1558,6 +1598,16 @@ static int lan78xx_phy_init(struct lan78xx_net *dev) | |||
1558 | return -EIO; | 1598 | return -EIO; |
1559 | } | 1599 | } |
1560 | 1600 | ||
1601 | /* Enable PHY interrupts. | ||
1602 | * We handle our own interrupt | ||
1603 | */ | ||
1604 | ret = phy_read(phydev, LAN88XX_INT_STS); | ||
1605 | ret = phy_write(phydev, LAN88XX_INT_MASK, | ||
1606 | LAN88XX_INT_MASK_MDINTPIN_EN_ | | ||
1607 | LAN88XX_INT_MASK_LINK_CHANGE_); | ||
1608 | |||
1609 | phydev->irq = PHY_IGNORE_INTERRUPT; | ||
1610 | |||
1561 | ret = phy_connect_direct(dev->net, phydev, | 1611 | ret = phy_connect_direct(dev->net, phydev, |
1562 | lan78xx_link_status_change, | 1612 | lan78xx_link_status_change, |
1563 | PHY_INTERFACE_MODE_GMII); | 1613 | PHY_INTERFACE_MODE_GMII); |
@@ -1580,14 +1630,6 @@ static int lan78xx_phy_init(struct lan78xx_net *dev) | |||
1580 | SUPPORTED_Pause | SUPPORTED_Asym_Pause); | 1630 | SUPPORTED_Pause | SUPPORTED_Asym_Pause); |
1581 | genphy_config_aneg(phydev); | 1631 | genphy_config_aneg(phydev); |
1582 | 1632 | ||
1583 | /* Workaround to enable PHY interrupt. | ||
1584 | * phy_start_interrupts() is API for requesting and enabling | ||
1585 | * PHY interrupt. However, USB-to-Ethernet device can't use | ||
1586 | * request_irq() called in phy_start_interrupts(). | ||
1587 | * Set PHY to PHY_HALTED and call phy_start() | ||
1588 | * to make a call to phy_enable_interrupts() | ||
1589 | */ | ||
1590 | phy_stop(phydev); | ||
1591 | phy_start(phydev); | 1633 | phy_start(phydev); |
1592 | 1634 | ||
1593 | netif_dbg(dev, ifup, dev->net, "phy initialised successfully"); | 1635 | netif_dbg(dev, ifup, dev->net, "phy initialised successfully"); |
@@ -2221,7 +2263,9 @@ netdev_tx_t lan78xx_start_xmit(struct sk_buff *skb, struct net_device *net) | |||
2221 | if (skb2) { | 2263 | if (skb2) { |
2222 | skb_queue_tail(&dev->txq_pend, skb2); | 2264 | skb_queue_tail(&dev->txq_pend, skb2); |
2223 | 2265 | ||
2224 | if (skb_queue_len(&dev->txq_pend) > 10) | 2266 | /* throttle TX patch at slower than SUPER SPEED USB */ |
2267 | if ((dev->udev->speed < USB_SPEED_SUPER) && | ||
2268 | (skb_queue_len(&dev->txq_pend) > 10)) | ||
2225 | netif_stop_queue(net); | 2269 | netif_stop_queue(net); |
2226 | } else { | 2270 | } else { |
2227 | netif_dbg(dev, tx_err, dev->net, | 2271 | netif_dbg(dev, tx_err, dev->net, |