sfc: Implement ndo_vlan_rx_{add, kill}_vid() callbacks
[deliverable/linux.git] / drivers / net / ethernet / sfc / efx.c
index 097f363f16309583412b97021e94244b926c9498..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);
@@ -2312,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,
@@ -2332,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,
@@ -3147,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.03748 seconds and 5 git commands to generate.