ibmvnic: Wait for device response when changing MAC
authorThomas Falcon <tlfalcon@linux.vnet.ibm.com>
Mon, 29 Jan 2018 19:45:05 +0000 (13:45 -0600)
committerDavid S. Miller <davem@davemloft.net>
Mon, 29 Jan 2018 23:03:24 +0000 (18:03 -0500)
Wait for a response from the VNIC server before exiting after setting
the MAC address. The resolves an issue with bonding a VNIC client in
ALB or TLB modes. The bonding driver was changing the MAC address more
rapidly than the device could respond, causing the following errors.

"bond0: the hw address of slave eth2 is in use by the bond;
couldn't find a slave with a free hw address to give it
(this should not have happened)"

If the function waits until the change is finalized, these errors are
avoided.

Signed-off-by: Thomas Falcon <tlfalcon@linux.vnet.ibm.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/ethernet/ibm/ibmvnic.c

index 8f2a77e..8c3058d 100644 (file)
@@ -1548,15 +1548,19 @@ static int __ibmvnic_set_mac(struct net_device *netdev, struct sockaddr *p)
        crq.change_mac_addr.first = IBMVNIC_CRQ_CMD;
        crq.change_mac_addr.cmd = CHANGE_MAC_ADDR;
        ether_addr_copy(&crq.change_mac_addr.mac_addr[0], addr->sa_data);
+
+       init_completion(&adapter->fw_done);
        ibmvnic_send_crq(adapter, &crq);
+       wait_for_completion(&adapter->fw_done);
        /* netdev->dev_addr is changed in handle_change_mac_rsp function */
-       return 0;
+       return adapter->fw_done_rc ? -EIO : 0;
 }
 
 static int ibmvnic_set_mac(struct net_device *netdev, void *p)
 {
        struct ibmvnic_adapter *adapter = netdev_priv(netdev);
        struct sockaddr *addr = p;
+       int rc;
 
        if (adapter->state == VNIC_PROBED) {
                memcpy(&adapter->desired.mac, addr, sizeof(struct sockaddr));
@@ -1564,9 +1568,9 @@ static int ibmvnic_set_mac(struct net_device *netdev, void *p)
                return 0;
        }
 
-       __ibmvnic_set_mac(netdev, addr);
+       rc = __ibmvnic_set_mac(netdev, addr);
 
-       return 0;
+       return rc;
 }
 
 /**
@@ -3569,8 +3573,8 @@ static void handle_error_indication(union ibmvnic_crq *crq,
                ibmvnic_reset(adapter, VNIC_RESET_NON_FATAL);
 }
 
-static void handle_change_mac_rsp(union ibmvnic_crq *crq,
-                                 struct ibmvnic_adapter *adapter)
+static int handle_change_mac_rsp(union ibmvnic_crq *crq,
+                                struct ibmvnic_adapter *adapter)
 {
        struct net_device *netdev = adapter->netdev;
        struct device *dev = &adapter->vdev->dev;
@@ -3579,10 +3583,13 @@ static void handle_change_mac_rsp(union ibmvnic_crq *crq,
        rc = crq->change_mac_addr_rsp.rc.code;
        if (rc) {
                dev_err(dev, "Error %ld in CHANGE_MAC_ADDR_RSP\n", rc);
-               return;
+               goto out;
        }
        memcpy(netdev->dev_addr, &crq->change_mac_addr_rsp.mac_addr[0],
               ETH_ALEN);
+out:
+       complete(&adapter->fw_done);
+       return rc;
 }
 
 static void handle_request_cap_rsp(union ibmvnic_crq *crq,
@@ -4042,7 +4049,7 @@ static void ibmvnic_handle_crq(union ibmvnic_crq *crq,
                break;
        case CHANGE_MAC_ADDR_RSP:
                netdev_dbg(netdev, "Got MAC address change Response\n");
-               handle_change_mac_rsp(crq, adapter);
+               adapter->fw_done_rc = handle_change_mac_rsp(crq, adapter);
                break;
        case ERROR_INDICATION:
                netdev_dbg(netdev, "Got Error Indication\n");