sfc: Implement ndo_vlan_rx_{add, kill}_vid() callbacks
[deliverable/linux.git] / drivers / net / ethernet / sfc / efx.c
index 0705ec869487921f89252c8ef99420375a83f491..902bcf292b0953e9abe6fc3755e8122b7f44387a 100644 (file)
@@ -600,6 +600,7 @@ fail:
  */
 static void efx_start_datapath(struct efx_nic *efx)
 {
+       netdev_features_t old_features = efx->net_dev->features;
        bool old_rx_scatter = efx->rx_scatter;
        struct efx_tx_queue *tx_queue;
        struct efx_rx_queue *rx_queue;
@@ -644,6 +645,15 @@ static void efx_start_datapath(struct efx_nic *efx)
                          efx->rx_dma_len, efx->rx_page_buf_step,
                          efx->rx_bufs_per_page, efx->rx_pages_per_batch);
 
+       /* Restore previously fixed features in hw_features and remove
+        * features which are fixed now
+        */
+       efx->net_dev->hw_features |= efx->net_dev->features;
+       efx->net_dev->hw_features &= ~efx->fixed_features;
+       efx->net_dev->features |= efx->fixed_features;
+       if (efx->net_dev->features != old_features)
+               netdev_features_change(efx->net_dev);
+
        /* RX filters may also have scatter-enabled flags */
        if (efx->rx_scatter != old_rx_scatter)
                efx->type->filter_update_rx_scatter(efx);
@@ -1726,14 +1736,33 @@ static int efx_probe_filters(struct efx_nic *efx)
 
 #ifdef CONFIG_RFS_ACCEL
        if (efx->type->offload_features & NETIF_F_NTUPLE) {
-               efx->rps_flow_id = kcalloc(efx->type->max_rx_ip_filters,
-                                          sizeof(*efx->rps_flow_id),
-                                          GFP_KERNEL);
-               if (!efx->rps_flow_id) {
+               struct efx_channel *channel;
+               int i, success = 1;
+
+               efx_for_each_channel(channel, efx) {
+                       channel->rps_flow_id =
+                               kcalloc(efx->type->max_rx_ip_filters,
+                                       sizeof(*channel->rps_flow_id),
+                                       GFP_KERNEL);
+                       if (!channel->rps_flow_id)
+                               success = 0;
+                       else
+                               for (i = 0;
+                                    i < efx->type->max_rx_ip_filters;
+                                    ++i)
+                                       channel->rps_flow_id[i] =
+                                               RPS_FLOW_ID_INVALID;
+               }
+
+               if (!success) {
+                       efx_for_each_channel(channel, efx)
+                               kfree(channel->rps_flow_id);
                        efx->type->filter_table_remove(efx);
                        rc = -ENOMEM;
                        goto out_unlock;
                }
+
+               efx->rps_expire_index = efx->rps_expire_channel = 0;
        }
 #endif
 out_unlock:
@@ -1744,7 +1773,10 @@ out_unlock:
 static void efx_remove_filters(struct efx_nic *efx)
 {
 #ifdef CONFIG_RFS_ACCEL
-       kfree(efx->rps_flow_id);
+       struct efx_channel *channel;
+
+       efx_for_each_channel(channel, efx)
+               kfree(channel->rps_flow_id);
 #endif
        down_write(&efx->filter_sem);
        efx->type->filter_table_remove(efx);
@@ -2290,14 +2322,46 @@ static void efx_set_rx_mode(struct net_device *net_dev)
 static int efx_set_features(struct net_device *net_dev, netdev_features_t data)
 {
        struct efx_nic *efx = netdev_priv(net_dev);
+       int rc;
 
        /* If disabling RX n-tuple filtering, clear existing filters */
-       if (net_dev->features & ~data & NETIF_F_NTUPLE)
-               return efx->type->filter_clear_rx(efx, EFX_FILTER_PRI_MANUAL);
+       if (net_dev->features & ~data & NETIF_F_NTUPLE) {
+               rc = efx->type->filter_clear_rx(efx, EFX_FILTER_PRI_MANUAL);
+               if (rc)
+                       return rc;
+       }
+
+       /* If Rx VLAN filter is changed, update filters via mac_reconfigure */
+       if ((net_dev->features ^ data) & NETIF_F_HW_VLAN_CTAG_FILTER) {
+               /* efx_set_rx_mode() will schedule MAC work to update filters
+                * when a new features are finally set in net_dev.
+                */
+               efx_set_rx_mode(net_dev);
+       }
 
        return 0;
 }
 
+static int efx_vlan_rx_add_vid(struct net_device *net_dev, __be16 proto, u16 vid)
+{
+       struct efx_nic *efx = netdev_priv(net_dev);
+
+       if (efx->type->vlan_rx_add_vid)
+               return efx->type->vlan_rx_add_vid(efx, proto, vid);
+       else
+               return -EOPNOTSUPP;
+}
+
+static int efx_vlan_rx_kill_vid(struct net_device *net_dev, __be16 proto, u16 vid)
+{
+       struct efx_nic *efx = netdev_priv(net_dev);
+
+       if (efx->type->vlan_rx_kill_vid)
+               return efx->type->vlan_rx_kill_vid(efx, proto, vid);
+       else
+               return -EOPNOTSUPP;
+}
+
 static const struct net_device_ops efx_netdev_ops = {
        .ndo_open               = efx_net_open,
        .ndo_stop               = efx_net_stop,
@@ -2310,6 +2374,8 @@ static const struct net_device_ops efx_netdev_ops = {
        .ndo_set_mac_address    = efx_set_mac_address,
        .ndo_set_rx_mode        = efx_set_rx_mode,
        .ndo_set_features       = efx_set_features,
+       .ndo_vlan_rx_add_vid    = efx_vlan_rx_add_vid,
+       .ndo_vlan_rx_kill_vid   = efx_vlan_rx_kill_vid,
 #ifdef CONFIG_SFC_SRIOV
        .ndo_set_vf_mac         = efx_sriov_set_vf_mac,
        .ndo_set_vf_vlan        = efx_sriov_set_vf_vlan,
@@ -3125,17 +3191,17 @@ static int efx_pci_probe(struct pci_dev *pci_dev,
                return -ENOMEM;
        efx = netdev_priv(net_dev);
        efx->type = (const struct efx_nic_type *) entry->driver_data;
+       efx->fixed_features |= NETIF_F_HIGHDMA;
        net_dev->features |= (efx->type->offload_features | NETIF_F_SG |
-                             NETIF_F_HIGHDMA | NETIF_F_TSO |
-                             NETIF_F_RXCSUM);
+                             NETIF_F_TSO | NETIF_F_RXCSUM);
        if (efx->type->offload_features & (NETIF_F_IPV6_CSUM | NETIF_F_HW_CSUM))
                net_dev->features |= NETIF_F_TSO6;
        /* Mask for features that also apply to VLAN devices */
        net_dev->vlan_features |= (NETIF_F_HW_CSUM | NETIF_F_SG |
                                   NETIF_F_HIGHDMA | NETIF_F_ALL_TSO |
                                   NETIF_F_RXCSUM);
-       /* All offloads can be toggled */
-       net_dev->hw_features = net_dev->features & ~NETIF_F_HIGHDMA;
+       net_dev->features |= efx->fixed_features;
+       net_dev->hw_features = net_dev->features & ~efx->fixed_features;
        pci_set_drvdata(pci_dev, efx);
        SET_NETDEV_DEV(net_dev, &pci_dev->dev);
        rc = efx_init_struct(efx, pci_dev, net_dev);
This page took 0.043703 seconds and 5 git commands to generate.