Commit a77ce1bc authored by David S. Miller's avatar David S. Miller

Merge branch 'lan78xx-fixes'

Woojung Huh says:

====================
lan78xx: update and fixes

  lan78xx: change to use updated phy-ignore-interrupts
  lan78xx: Add to handle mux control per chip id
  lan78xx: throttle TX path at slower than SuperSpeed USB
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents ff5d7497 4b2a4a96
...@@ -36,7 +36,7 @@ ...@@ -36,7 +36,7 @@
#define DRIVER_AUTHOR "WOOJUNG HUH <woojung.huh@microchip.com>" #define DRIVER_AUTHOR "WOOJUNG HUH <woojung.huh@microchip.com>"
#define DRIVER_DESC "LAN78XX USB 3.0 Gigabit Ethernet Devices" #define DRIVER_DESC "LAN78XX USB 3.0 Gigabit Ethernet Devices"
#define DRIVER_NAME "lan78xx" #define DRIVER_NAME "lan78xx"
#define DRIVER_VERSION "1.0.1" #define DRIVER_VERSION "1.0.2"
#define TX_TIMEOUT_JIFFIES (5 * HZ) #define TX_TIMEOUT_JIFFIES (5 * HZ)
#define THROTTLE_JIFFIES (HZ / 8) #define THROTTLE_JIFFIES (HZ / 8)
...@@ -462,32 +462,53 @@ static int lan78xx_read_raw_eeprom(struct lan78xx_net *dev, u32 offset, ...@@ -462,32 +462,53 @@ static int lan78xx_read_raw_eeprom(struct lan78xx_net *dev, u32 offset,
u32 length, u8 *data) u32 length, u8 *data)
{ {
u32 val; u32 val;
u32 saved;
int i, ret; int i, ret;
int retval;
ret = lan78xx_eeprom_confirm_not_busy(dev); /* depends on chip, some EEPROM pins are muxed with LED function.
if (ret) * disable & restore LED function to access EEPROM.
return ret; */
ret = lan78xx_read_reg(dev, HW_CFG, &val);
saved = val;
if ((dev->devid & ID_REV_CHIP_ID_MASK_) == 0x78000000) {
val &= ~(HW_CFG_LED1_EN_ | HW_CFG_LED0_EN_);
ret = lan78xx_write_reg(dev, HW_CFG, val);
}
retval = lan78xx_eeprom_confirm_not_busy(dev);
if (retval)
return retval;
for (i = 0; i < length; i++) { for (i = 0; i < length; i++) {
val = E2P_CMD_EPC_BUSY_ | E2P_CMD_EPC_CMD_READ_; val = E2P_CMD_EPC_BUSY_ | E2P_CMD_EPC_CMD_READ_;
val |= (offset & E2P_CMD_EPC_ADDR_MASK_); val |= (offset & E2P_CMD_EPC_ADDR_MASK_);
ret = lan78xx_write_reg(dev, E2P_CMD, val); ret = lan78xx_write_reg(dev, E2P_CMD, val);
if (unlikely(ret < 0)) if (unlikely(ret < 0)) {
return -EIO; retval = -EIO;
goto exit;
}
ret = lan78xx_wait_eeprom(dev); retval = lan78xx_wait_eeprom(dev);
if (ret < 0) if (retval < 0)
return ret; goto exit;
ret = lan78xx_read_reg(dev, E2P_DATA, &val); ret = lan78xx_read_reg(dev, E2P_DATA, &val);
if (unlikely(ret < 0)) if (unlikely(ret < 0)) {
return -EIO; retval = -EIO;
goto exit;
}
data[i] = val & 0xFF; data[i] = val & 0xFF;
offset++; offset++;
} }
return 0; retval = 0;
exit:
if ((dev->devid & ID_REV_CHIP_ID_MASK_) == 0x78000000)
ret = lan78xx_write_reg(dev, HW_CFG, saved);
return retval;
} }
static int lan78xx_read_eeprom(struct lan78xx_net *dev, u32 offset, 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,44 +530,67 @@ static int lan78xx_write_raw_eeprom(struct lan78xx_net *dev, u32 offset,
u32 length, u8 *data) u32 length, u8 *data)
{ {
u32 val; u32 val;
u32 saved;
int i, ret; int i, ret;
int retval;
ret = lan78xx_eeprom_confirm_not_busy(dev); /* depends on chip, some EEPROM pins are muxed with LED function.
if (ret) * disable & restore LED function to access EEPROM.
return ret; */
ret = lan78xx_read_reg(dev, HW_CFG, &val);
saved = val;
if ((dev->devid & ID_REV_CHIP_ID_MASK_) == 0x78000000) {
val &= ~(HW_CFG_LED1_EN_ | HW_CFG_LED0_EN_);
ret = lan78xx_write_reg(dev, HW_CFG, val);
}
retval = lan78xx_eeprom_confirm_not_busy(dev);
if (retval)
goto exit;
/* Issue write/erase enable command */ /* Issue write/erase enable command */
val = E2P_CMD_EPC_BUSY_ | E2P_CMD_EPC_CMD_EWEN_; val = E2P_CMD_EPC_BUSY_ | E2P_CMD_EPC_CMD_EWEN_;
ret = lan78xx_write_reg(dev, E2P_CMD, val); ret = lan78xx_write_reg(dev, E2P_CMD, val);
if (unlikely(ret < 0)) if (unlikely(ret < 0)) {
return -EIO; retval = -EIO;
goto exit;
}
ret = lan78xx_wait_eeprom(dev); retval = lan78xx_wait_eeprom(dev);
if (ret < 0) if (retval < 0)
return ret; goto exit;
for (i = 0; i < length; i++) { for (i = 0; i < length; i++) {
/* Fill data register */ /* Fill data register */
val = data[i]; val = data[i];
ret = lan78xx_write_reg(dev, E2P_DATA, val); ret = lan78xx_write_reg(dev, E2P_DATA, val);
if (ret < 0) if (ret < 0) {
return ret; retval = -EIO;
goto exit;
}
/* Send "write" command */ /* Send "write" command */
val = E2P_CMD_EPC_BUSY_ | E2P_CMD_EPC_CMD_WRITE_; val = E2P_CMD_EPC_BUSY_ | E2P_CMD_EPC_CMD_WRITE_;
val |= (offset & E2P_CMD_EPC_ADDR_MASK_); val |= (offset & E2P_CMD_EPC_ADDR_MASK_);
ret = lan78xx_write_reg(dev, E2P_CMD, val); ret = lan78xx_write_reg(dev, E2P_CMD, val);
if (ret < 0) if (ret < 0) {
return ret; retval = -EIO;
goto exit;
}
ret = lan78xx_wait_eeprom(dev); retval = lan78xx_wait_eeprom(dev);
if (ret < 0) if (retval < 0)
return ret; goto exit;
offset++; offset++;
} }
return 0; retval = 0;
exit:
if ((dev->devid & ID_REV_CHIP_ID_MASK_) == 0x78000000)
ret = lan78xx_write_reg(dev, HW_CFG, saved);
return retval;
} }
static int lan78xx_read_raw_otp(struct lan78xx_net *dev, u32 offset, 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,7 +948,6 @@ static int lan78xx_link_reset(struct lan78xx_net *dev)
if (!phydev->link && dev->link_on) { if (!phydev->link && dev->link_on) {
dev->link_on = false; dev->link_on = false;
netif_carrier_off(dev->net);
/* reset MAC */ /* reset MAC */
ret = lan78xx_read_reg(dev, MAC_CR, &buf); ret = lan78xx_read_reg(dev, MAC_CR, &buf);
...@@ -914,6 +957,8 @@ static int lan78xx_link_reset(struct lan78xx_net *dev) ...@@ -914,6 +957,8 @@ static int lan78xx_link_reset(struct lan78xx_net *dev)
ret = lan78xx_write_reg(dev, MAC_CR, buf); ret = lan78xx_write_reg(dev, MAC_CR, buf);
if (unlikely(ret < 0)) if (unlikely(ret < 0))
return -EIO; return -EIO;
phy_mac_interrupt(phydev, 0);
} else if (phydev->link && !dev->link_on) { } else if (phydev->link && !dev->link_on) {
dev->link_on = true; dev->link_on = true;
...@@ -953,7 +998,7 @@ static int lan78xx_link_reset(struct lan78xx_net *dev) ...@@ -953,7 +998,7 @@ static int lan78xx_link_reset(struct lan78xx_net *dev)
ethtool_cmd_speed(&ecmd), ecmd.duplex, ladv, radv); ethtool_cmd_speed(&ecmd), ecmd.duplex, ladv, radv);
ret = lan78xx_update_flowcontrol(dev, ecmd.duplex, ladv, radv); ret = lan78xx_update_flowcontrol(dev, ecmd.duplex, ladv, radv);
netif_carrier_on(dev->net); phy_mac_interrupt(phydev, 1);
} }
return ret; return ret;
...@@ -1495,7 +1540,6 @@ static int lan78xx_mdiobus_write(struct mii_bus *bus, int phy_id, int idx, ...@@ -1495,7 +1540,6 @@ static int lan78xx_mdiobus_write(struct mii_bus *bus, int phy_id, int idx,
static int lan78xx_mdio_init(struct lan78xx_net *dev) static int lan78xx_mdio_init(struct lan78xx_net *dev)
{ {
int ret; int ret;
int i;
dev->mdiobus = mdiobus_alloc(); dev->mdiobus = mdiobus_alloc();
if (!dev->mdiobus) { if (!dev->mdiobus) {
...@@ -1511,10 +1555,6 @@ static int lan78xx_mdio_init(struct lan78xx_net *dev) ...@@ -1511,10 +1555,6 @@ static int lan78xx_mdio_init(struct lan78xx_net *dev)
snprintf(dev->mdiobus->id, MII_BUS_ID_SIZE, "usb-%03d:%03d", snprintf(dev->mdiobus->id, MII_BUS_ID_SIZE, "usb-%03d:%03d",
dev->udev->bus->busnum, dev->udev->devnum); dev->udev->bus->busnum, dev->udev->devnum);
/* handle our own interrupt */
for (i = 0; i < PHY_MAX_ADDR; i++)
dev->mdiobus->irq[i] = PHY_IGNORE_INTERRUPT;
switch (dev->devid & ID_REV_CHIP_ID_MASK_) { switch (dev->devid & ID_REV_CHIP_ID_MASK_) {
case 0x78000000: case 0x78000000:
case 0x78500000: case 0x78500000:
...@@ -1558,6 +1598,16 @@ static int lan78xx_phy_init(struct lan78xx_net *dev) ...@@ -1558,6 +1598,16 @@ static int lan78xx_phy_init(struct lan78xx_net *dev)
return -EIO; return -EIO;
} }
/* Enable PHY interrupts.
* We handle our own interrupt
*/
ret = phy_read(phydev, LAN88XX_INT_STS);
ret = phy_write(phydev, LAN88XX_INT_MASK,
LAN88XX_INT_MASK_MDINTPIN_EN_ |
LAN88XX_INT_MASK_LINK_CHANGE_);
phydev->irq = PHY_IGNORE_INTERRUPT;
ret = phy_connect_direct(dev->net, phydev, ret = phy_connect_direct(dev->net, phydev,
lan78xx_link_status_change, lan78xx_link_status_change,
PHY_INTERFACE_MODE_GMII); PHY_INTERFACE_MODE_GMII);
...@@ -1580,14 +1630,6 @@ static int lan78xx_phy_init(struct lan78xx_net *dev) ...@@ -1580,14 +1630,6 @@ static int lan78xx_phy_init(struct lan78xx_net *dev)
SUPPORTED_Pause | SUPPORTED_Asym_Pause); SUPPORTED_Pause | SUPPORTED_Asym_Pause);
genphy_config_aneg(phydev); genphy_config_aneg(phydev);
/* Workaround to enable PHY interrupt.
* phy_start_interrupts() is API for requesting and enabling
* PHY interrupt. However, USB-to-Ethernet device can't use
* request_irq() called in phy_start_interrupts().
* Set PHY to PHY_HALTED and call phy_start()
* to make a call to phy_enable_interrupts()
*/
phy_stop(phydev);
phy_start(phydev); phy_start(phydev);
netif_dbg(dev, ifup, dev->net, "phy initialised successfully"); 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,7 +2263,9 @@ netdev_tx_t lan78xx_start_xmit(struct sk_buff *skb, struct net_device *net)
if (skb2) { if (skb2) {
skb_queue_tail(&dev->txq_pend, skb2); skb_queue_tail(&dev->txq_pend, skb2);
if (skb_queue_len(&dev->txq_pend) > 10) /* throttle TX patch at slower than SUPER SPEED USB */
if ((dev->udev->speed < USB_SPEED_SUPER) &&
(skb_queue_len(&dev->txq_pend) > 10))
netif_stop_queue(net); netif_stop_queue(net);
} else { } else {
netif_dbg(dev, tx_err, dev->net, netif_dbg(dev, tx_err, dev->net,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment