fm10k: Unlock mailbox on VLAN addition failures
[deliverable/linux.git] / drivers / net / ethernet / intel / fm10k / fm10k_netdev.c
index 268966bfe019d70bcee6313e121be32194552491..b57ea1c09a21aacec533a10547a20acf6616f995 100644 (file)
@@ -243,6 +243,9 @@ void fm10k_clean_all_tx_rings(struct fm10k_intfc *interface)
 
        for (i = 0; i < interface->num_tx_queues; i++)
                fm10k_clean_tx_ring(interface->tx_ring[i]);
+
+       /* remove any stale timestamp buffers and free them */
+       skb_queue_purge(&interface->ts_tx_skb_queue);
 }
 
 /**
@@ -368,7 +371,21 @@ static void fm10k_request_glort_range(struct fm10k_intfc *interface)
        if (hw->mac.dglort_map == FM10K_DGLORTMAP_NONE)
                return;
 
-       interface->glort_count = mask + 1;
+       /* we support 3 possible GLORT configurations.
+        * 1: VFs consume all but the last 1
+        * 2: VFs and PF split glorts with possible gap between
+        * 3: VFs allocated first 64, all others belong to PF
+        */
+       if (mask <= hw->iov.total_vfs) {
+               interface->glort_count = 1;
+               interface->glort += mask;
+       } else if (mask < 64) {
+               interface->glort_count = (mask + 1) / 2;
+               interface->glort += interface->glort_count;
+       } else {
+               interface->glort_count = mask - 63;
+               interface->glort += 64;
+       }
 }
 
 /**
@@ -529,6 +546,10 @@ int fm10k_open(struct net_device *netdev)
        fm10k_request_glort_range(interface);
 
        /* Notify the stack of the actual queue counts */
+       err = netif_set_real_num_tx_queues(netdev,
+                                          interface->num_tx_queues);
+       if (err)
+               goto err_set_queues;
 
        err = netif_set_real_num_rx_queues(netdev,
                                           interface->num_rx_queues);
@@ -584,7 +605,7 @@ int fm10k_close(struct net_device *netdev)
 static netdev_tx_t fm10k_xmit_frame(struct sk_buff *skb, struct net_device *dev)
 {
        struct fm10k_intfc *interface = netdev_priv(dev);
-       unsigned int r_idx = 0;
+       unsigned int r_idx = skb->queue_mapping;
        int err;
 
        if ((skb->protocol ==  htons(ETH_P_8021Q)) &&
@@ -637,6 +658,10 @@ static netdev_tx_t fm10k_xmit_frame(struct sk_buff *skb, struct net_device *dev)
                __skb_put(skb, pad_len);
        }
 
+       /* prepare packet for hardware time stamping */
+       if (unlikely(skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP))
+               fm10k_ts_tx_enqueue(interface, skb);
+
        if (r_idx >= interface->num_tx_queues)
                r_idx %= interface->num_tx_queues;
 
@@ -760,14 +785,14 @@ static int fm10k_update_vid(struct net_device *netdev, u16 vid, bool set)
        if (!(netdev->flags & IFF_PROMISC)) {
                err = hw->mac.ops.update_vlan(hw, vid, 0, set);
                if (err)
-                       return err;
+                       goto err_out;
        }
 
        /* update our base MAC address */
        err = hw->mac.ops.update_uc_addr(hw, interface->glort, hw->mac.addr,
                                         vid, set, 0);
        if (err)
-               return err;
+               goto err_out;
 
        /* set vid prior to syncing/unsyncing the VLAN */
        interface->vid = vid + (set ? VLAN_N_VID : 0);
@@ -776,9 +801,10 @@ static int fm10k_update_vid(struct net_device *netdev, u16 vid, bool set)
        __dev_uc_unsync(netdev, fm10k_uc_vlan_unsync);
        __dev_mc_unsync(netdev, fm10k_mc_vlan_unsync);
 
+err_out:
        fm10k_mbx_unlock(interface);
 
-       return 0;
+       return err;
 }
 
 static int fm10k_vlan_rx_add_vid(struct net_device *netdev,
@@ -976,6 +1002,21 @@ void fm10k_restore_rx_state(struct fm10k_intfc *interface)
        int xcast_mode;
        u16 vid, glort;
 
+       /* restore our address if perm_addr is set */
+       if (hw->mac.type == fm10k_mac_vf) {
+               if (is_valid_ether_addr(hw->mac.perm_addr)) {
+                       ether_addr_copy(hw->mac.addr, hw->mac.perm_addr);
+                       ether_addr_copy(netdev->perm_addr, hw->mac.perm_addr);
+                       ether_addr_copy(netdev->dev_addr, hw->mac.perm_addr);
+                       netdev->addr_assign_type &= ~NET_ADDR_RANDOM;
+               }
+
+               if (hw->mac.vlan_override)
+                       netdev->features &= ~NETIF_F_HW_VLAN_CTAG_RX;
+               else
+                       netdev->features |= NETIF_F_HW_VLAN_CTAG_RX;
+       }
+
        /* record glort for this interface */
        glort = interface->glort;
 
@@ -1148,6 +1189,18 @@ int fm10k_setup_tc(struct net_device *dev, u8 tc)
        return 0;
 }
 
+static int fm10k_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd)
+{
+       switch (cmd) {
+       case SIOCGHWTSTAMP:
+               return fm10k_get_ts_config(netdev, ifr);
+       case SIOCSHWTSTAMP:
+               return fm10k_set_ts_config(netdev, ifr);
+       default:
+               return -EOPNOTSUPP;
+       }
+}
+
 static void fm10k_assign_l2_accel(struct fm10k_intfc *interface,
                                  struct fm10k_l2_accel *l2_accel)
 {
@@ -1310,8 +1363,13 @@ static const struct net_device_ops fm10k_netdev_ops = {
        .ndo_set_rx_mode        = fm10k_set_rx_mode,
        .ndo_get_stats64        = fm10k_get_stats64,
        .ndo_setup_tc           = fm10k_setup_tc,
+       .ndo_set_vf_mac         = fm10k_ndo_set_vf_mac,
+       .ndo_set_vf_vlan        = fm10k_ndo_set_vf_vlan,
+       .ndo_set_vf_rate        = fm10k_ndo_set_vf_bw,
+       .ndo_get_vf_config      = fm10k_ndo_get_vf_config,
        .ndo_add_vxlan_port     = fm10k_add_vxlan_port,
        .ndo_del_vxlan_port     = fm10k_del_vxlan_port,
+       .ndo_do_ioctl           = fm10k_ioctl,
        .ndo_dfwd_add_station   = fm10k_dfwd_add_station,
        .ndo_dfwd_del_station   = fm10k_dfwd_del_station,
 };
This page took 0.025933 seconds and 5 git commands to generate.