Commit 4b222008 authored by Gerhard Engleder's avatar Gerhard Engleder Committed by David S. Miller

tsnep: Add loopback support

Add support for NETIF_F_LOOPBACK feature. Loopback mode is used for
testing.
Signed-off-by: default avatarGerhard Engleder <gerhard@engleder-embedded.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 7d8dd6b5
...@@ -124,14 +124,11 @@ static int tsnep_mdiobus_write(struct mii_bus *bus, int addr, int regnum, ...@@ -124,14 +124,11 @@ static int tsnep_mdiobus_write(struct mii_bus *bus, int addr, int regnum,
return 0; return 0;
} }
static void tsnep_phy_link_status_change(struct net_device *netdev) static void tsnep_set_link_mode(struct tsnep_adapter *adapter)
{ {
struct tsnep_adapter *adapter = netdev_priv(netdev);
struct phy_device *phydev = netdev->phydev;
u32 mode; u32 mode;
if (phydev->link) { switch (adapter->phydev->speed) {
switch (phydev->speed) {
case SPEED_100: case SPEED_100:
mode = ECM_LINK_MODE_100; mode = ECM_LINK_MODE_100;
break; break;
...@@ -143,11 +140,35 @@ static void tsnep_phy_link_status_change(struct net_device *netdev) ...@@ -143,11 +140,35 @@ static void tsnep_phy_link_status_change(struct net_device *netdev)
break; break;
} }
iowrite32(mode, adapter->addr + ECM_STATUS); iowrite32(mode, adapter->addr + ECM_STATUS);
} }
static void tsnep_phy_link_status_change(struct net_device *netdev)
{
struct tsnep_adapter *adapter = netdev_priv(netdev);
struct phy_device *phydev = netdev->phydev;
if (phydev->link)
tsnep_set_link_mode(adapter);
phy_print_status(netdev->phydev); phy_print_status(netdev->phydev);
} }
static int tsnep_phy_loopback(struct tsnep_adapter *adapter, bool enable)
{
int retval;
retval = phy_loopback(adapter->phydev, enable);
/* PHY link state change is not signaled if loopback is enabled, it
* would delay a working loopback anyway, let's ensure that loopback
* is working immediately by setting link mode directly
*/
if (!retval && enable)
tsnep_set_link_mode(adapter);
return retval;
}
static int tsnep_phy_open(struct tsnep_adapter *adapter) static int tsnep_phy_open(struct tsnep_adapter *adapter)
{ {
struct phy_device *phydev; struct phy_device *phydev;
...@@ -1017,6 +1038,22 @@ static int tsnep_netdev_set_mac_address(struct net_device *netdev, void *addr) ...@@ -1017,6 +1038,22 @@ static int tsnep_netdev_set_mac_address(struct net_device *netdev, void *addr)
return 0; return 0;
} }
static int tsnep_netdev_set_features(struct net_device *netdev,
netdev_features_t features)
{
struct tsnep_adapter *adapter = netdev_priv(netdev);
netdev_features_t changed = netdev->features ^ features;
bool enable;
int retval = 0;
if (changed & NETIF_F_LOOPBACK) {
enable = !!(features & NETIF_F_LOOPBACK);
retval = tsnep_phy_loopback(adapter, enable);
}
return retval;
}
static ktime_t tsnep_netdev_get_tstamp(struct net_device *netdev, static ktime_t tsnep_netdev_get_tstamp(struct net_device *netdev,
const struct skb_shared_hwtstamps *hwtstamps, const struct skb_shared_hwtstamps *hwtstamps,
bool cycles) bool cycles)
...@@ -1038,9 +1075,9 @@ static const struct net_device_ops tsnep_netdev_ops = { ...@@ -1038,9 +1075,9 @@ static const struct net_device_ops tsnep_netdev_ops = {
.ndo_start_xmit = tsnep_netdev_xmit_frame, .ndo_start_xmit = tsnep_netdev_xmit_frame,
.ndo_eth_ioctl = tsnep_netdev_ioctl, .ndo_eth_ioctl = tsnep_netdev_ioctl,
.ndo_set_rx_mode = tsnep_netdev_set_multicast, .ndo_set_rx_mode = tsnep_netdev_set_multicast,
.ndo_get_stats64 = tsnep_netdev_get_stats64, .ndo_get_stats64 = tsnep_netdev_get_stats64,
.ndo_set_mac_address = tsnep_netdev_set_mac_address, .ndo_set_mac_address = tsnep_netdev_set_mac_address,
.ndo_set_features = tsnep_netdev_set_features,
.ndo_get_tstamp = tsnep_netdev_get_tstamp, .ndo_get_tstamp = tsnep_netdev_get_tstamp,
.ndo_setup_tc = tsnep_tc_setup, .ndo_setup_tc = tsnep_tc_setup,
}; };
...@@ -1225,7 +1262,7 @@ static int tsnep_probe(struct platform_device *pdev) ...@@ -1225,7 +1262,7 @@ static int tsnep_probe(struct platform_device *pdev)
netdev->netdev_ops = &tsnep_netdev_ops; netdev->netdev_ops = &tsnep_netdev_ops;
netdev->ethtool_ops = &tsnep_ethtool_ops; netdev->ethtool_ops = &tsnep_ethtool_ops;
netdev->features = NETIF_F_SG; netdev->features = NETIF_F_SG;
netdev->hw_features = netdev->features; netdev->hw_features = netdev->features | NETIF_F_LOOPBACK;
/* carrier off reporting is important to ethtool even BEFORE open */ /* carrier off reporting is important to ethtool even BEFORE open */
netif_carrier_off(netdev); netif_carrier_off(netdev);
......
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