This patch resolves an issue with sensitive bonding modes that require valid speed and duplex settings to function properly. Currently, the adapter will report that device speed and duplex is unknown if the communication link with firmware is unavailable. This decision can break LACP configurations if the timing is right.
For example, if invalid speeds are reported, the slave device's link state is set to a transitional "fail" state and the LACP port is disabled. However, if valid speeds are reported later but the link state has not been altered, the LACP port will remain disabled. If the link state then transitions back to "up" from "fail," it results in a state such that the slave reports valid speed/duplex and is up, but the LACP port will remain disabled. Workaround this by reporting the last recorded speed and duplex settings unless the device has never been activated. In that case or when the hypervisor gives invalid values, continue to report unknown speed or duplex to ethtool. Signed-off-by: Thomas Falcon <tlfal...@linux.ibm.com> --- drivers/net/ethernet/ibm/ibmvnic.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/net/ethernet/ibm/ibmvnic.c b/drivers/net/ethernet/ibm/ibmvnic.c index 3da6800..7c14e33 100644 --- a/drivers/net/ethernet/ibm/ibmvnic.c +++ b/drivers/net/ethernet/ibm/ibmvnic.c @@ -2276,10 +2276,8 @@ static int ibmvnic_get_link_ksettings(struct net_device *netdev, int rc; rc = send_query_phys_parms(adapter); - if (rc) { - adapter->speed = SPEED_UNKNOWN; - adapter->duplex = DUPLEX_UNKNOWN; - } + if (rc) + netdev_warn(netdev, "Device query of current speed and duplex settings failed; reported values may be stale.\n"); cmd->base.speed = adapter->speed; cmd->base.duplex = adapter->duplex; cmd->base.port = PORT_FIBRE; @@ -4834,6 +4832,8 @@ static int ibmvnic_probe(struct vio_dev *dev, const struct vio_device_id *id) dev_set_drvdata(&dev->dev, netdev); adapter->vdev = dev; adapter->netdev = netdev; + adapter->speed = SPEED_UNKNOWN; + adapter->duplex = DUPLEX_UNKNOWN; ether_addr_copy(adapter->mac_addr, mac_addr_p); ether_addr_copy(netdev->dev_addr, adapter->mac_addr); -- 1.8.3.1