Merge branches 'acpi-resources', 'acpi-battery', 'acpi-doc' and 'acpi-pnp'
[linux-2.6-block.git] / drivers / net / ethernet / mellanox / mlx4 / en_netdev.c
index ebce5bb24df98b77eec38a1fc6c720987768934b..32f5ec7374723d1315f4234f77b12ffbe5adcfe0 100644 (file)
@@ -1467,6 +1467,7 @@ static void mlx4_en_service_task(struct work_struct *work)
                if (mdev->dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_TS)
                        mlx4_en_ptp_overflow_check(mdev);
 
+               mlx4_en_recover_from_oom(priv);
                queue_delayed_work(mdev->workqueue, &priv->service_task,
                                   SERVICE_TASK_DELAY);
        }
@@ -1685,7 +1686,7 @@ int mlx4_en_start_port(struct net_device *dev)
        }
 
        /* Attach rx QP to bradcast address */
-       memset(&mc_list[10], 0xff, ETH_ALEN);
+       eth_broadcast_addr(&mc_list[10]);
        mc_list[5] = priv->port; /* needed for B0 steering support */
        if (mlx4_multicast_attach(mdev->dev, &priv->rss_map.indir_qp, mc_list,
                                  priv->port, 0, MLX4_PROT_ETH,
@@ -1721,7 +1722,7 @@ mac_err:
 cq_err:
        while (rx_index--) {
                mlx4_en_deactivate_cq(priv, priv->rx_cq[rx_index]);
-               mlx4_en_free_affinity_hint(priv, i);
+               mlx4_en_free_affinity_hint(priv, rx_index);
        }
        for (i = 0; i < priv->rx_ring_num; i++)
                mlx4_en_deactivate_rx_ring(priv, priv->rx_ring[i]);
@@ -1786,7 +1787,7 @@ void mlx4_en_stop_port(struct net_device *dev, int detach)
        }
 
        /* Detach All multicasts */
-       memset(&mc_list[10], 0xff, ETH_ALEN);
+       eth_broadcast_addr(&mc_list[10]);
        mc_list[5] = priv->port; /* needed for B0 steering support */
        mlx4_multicast_detach(mdev->dev, &priv->rss_map.indir_qp, mc_list,
                              MLX4_PROT_ETH, priv->broadcast_id);
@@ -1888,6 +1889,12 @@ static void mlx4_en_clear_stats(struct net_device *dev)
        memset(&priv->pstats, 0, sizeof(priv->pstats));
        memset(&priv->pkstats, 0, sizeof(priv->pkstats));
        memset(&priv->port_stats, 0, sizeof(priv->port_stats));
+       memset(&priv->rx_flowstats, 0, sizeof(priv->rx_flowstats));
+       memset(&priv->tx_flowstats, 0, sizeof(priv->tx_flowstats));
+       memset(&priv->rx_priority_flowstats, 0,
+              sizeof(priv->rx_priority_flowstats));
+       memset(&priv->tx_priority_flowstats, 0,
+              sizeof(priv->tx_priority_flowstats));
 
        for (i = 0; i < priv->tx_ring_num; i++) {
                priv->tx_ring[i]->bytes = 0;
@@ -2189,31 +2196,50 @@ static int mlx4_en_set_features(struct net_device *netdev,
                netdev_features_t features)
 {
        struct mlx4_en_priv *priv = netdev_priv(netdev);
+       bool reset = false;
        int ret = 0;
 
+       if (DEV_FEATURE_CHANGED(netdev, features, NETIF_F_RXFCS)) {
+               en_info(priv, "Turn %s RX-FCS\n",
+                       (features & NETIF_F_RXFCS) ? "ON" : "OFF");
+               reset = true;
+       }
+
+       if (DEV_FEATURE_CHANGED(netdev, features, NETIF_F_RXALL)) {
+               u8 ignore_fcs_value = (features & NETIF_F_RXALL) ? 1 : 0;
+
+               en_info(priv, "Turn %s RX-ALL\n",
+                       ignore_fcs_value ? "ON" : "OFF");
+               ret = mlx4_SET_PORT_fcs_check(priv->mdev->dev,
+                                             priv->port, ignore_fcs_value);
+               if (ret)
+                       return ret;
+       }
+
        if (DEV_FEATURE_CHANGED(netdev, features, NETIF_F_HW_VLAN_CTAG_RX)) {
                en_info(priv, "Turn %s RX vlan strip offload\n",
                        (features & NETIF_F_HW_VLAN_CTAG_RX) ? "ON" : "OFF");
-               ret = mlx4_en_reset_config(netdev, priv->hwtstamp_config,
-                                          features);
-               if (ret)
-                       return ret;
+               reset = true;
        }
 
        if (DEV_FEATURE_CHANGED(netdev, features, NETIF_F_HW_VLAN_CTAG_TX))
                en_info(priv, "Turn %s TX vlan strip offload\n",
                        (features & NETIF_F_HW_VLAN_CTAG_TX) ? "ON" : "OFF");
 
-       if (features & NETIF_F_LOOPBACK)
-               priv->ctrl_flags |= cpu_to_be32(MLX4_WQE_CTRL_FORCE_LOOPBACK);
-       else
-               priv->ctrl_flags &=
-                       cpu_to_be32(~MLX4_WQE_CTRL_FORCE_LOOPBACK);
+       if (DEV_FEATURE_CHANGED(netdev, features, NETIF_F_LOOPBACK)) {
+               en_info(priv, "Turn %s loopback\n",
+                       (features & NETIF_F_LOOPBACK) ? "ON" : "OFF");
+               mlx4_en_update_loopback_state(netdev, features);
+       }
 
-       mlx4_en_update_loopback_state(netdev, features);
+       if (reset) {
+               ret = mlx4_en_reset_config(netdev, priv->hwtstamp_config,
+                                          features);
+               if (ret)
+                       return ret;
+       }
 
        return 0;
-
 }
 
 static int mlx4_en_set_vf_mac(struct net_device *dev, int queue, u8 *mac)
@@ -2236,6 +2262,16 @@ static int mlx4_en_set_vf_vlan(struct net_device *dev, int vf, u16 vlan, u8 qos)
        return mlx4_set_vf_vlan(mdev->dev, en_priv->port, vf, vlan, qos);
 }
 
+static int mlx4_en_set_vf_rate(struct net_device *dev, int vf, int min_tx_rate,
+                              int max_tx_rate)
+{
+       struct mlx4_en_priv *en_priv = netdev_priv(dev);
+       struct mlx4_en_dev *mdev = en_priv->mdev;
+
+       return mlx4_set_vf_rate(mdev->dev, en_priv->port, vf, min_tx_rate,
+                               max_tx_rate);
+}
+
 static int mlx4_en_set_vf_spoofchk(struct net_device *dev, int vf, bool setting)
 {
        struct mlx4_en_priv *en_priv = netdev_priv(dev);
@@ -2373,10 +2409,38 @@ static netdev_features_t mlx4_en_features_check(struct sk_buff *skb,
                                                struct net_device *dev,
                                                netdev_features_t features)
 {
+       features = vlan_features_check(skb, features);
        return vxlan_features_check(skb, features);
 }
 #endif
 
+static int mlx4_en_set_tx_maxrate(struct net_device *dev, int queue_index, u32 maxrate)
+{
+       struct mlx4_en_priv *priv = netdev_priv(dev);
+       struct mlx4_en_tx_ring *tx_ring = priv->tx_ring[queue_index];
+       struct mlx4_update_qp_params params;
+       int err;
+
+       if (!(priv->mdev->dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_QP_RATE_LIMIT))
+               return -EOPNOTSUPP;
+
+       /* rate provided to us in Mbs, check if it fits into 12 bits, if not use Gbs */
+       if (maxrate >> 12) {
+               params.rate_unit = MLX4_QP_RATE_LIMIT_GBS;
+               params.rate_val  = maxrate / 1000;
+       } else if (maxrate) {
+               params.rate_unit = MLX4_QP_RATE_LIMIT_MBS;
+               params.rate_val  = maxrate;
+       } else { /* zero serves to revoke the QP rate-limitation */
+               params.rate_unit = 0;
+               params.rate_val  = 0;
+       }
+
+       err = mlx4_update_qp(priv->mdev->dev, tx_ring->qpn, MLX4_UPDATE_QP_RATE_LIMIT,
+                            &params);
+       return err;
+}
+
 static const struct net_device_ops mlx4_netdev_ops = {
        .ndo_open               = mlx4_en_open,
        .ndo_stop               = mlx4_en_close,
@@ -2408,6 +2472,7 @@ static const struct net_device_ops mlx4_netdev_ops = {
        .ndo_del_vxlan_port     = mlx4_en_del_vxlan_port,
        .ndo_features_check     = mlx4_en_features_check,
 #endif
+       .ndo_set_tx_maxrate     = mlx4_en_set_tx_maxrate,
 };
 
 static const struct net_device_ops mlx4_netdev_ops_master = {
@@ -2425,6 +2490,7 @@ static const struct net_device_ops mlx4_netdev_ops_master = {
        .ndo_vlan_rx_kill_vid   = mlx4_en_vlan_rx_kill_vid,
        .ndo_set_vf_mac         = mlx4_en_set_vf_mac,
        .ndo_set_vf_vlan        = mlx4_en_set_vf_vlan,
+       .ndo_set_vf_rate        = mlx4_en_set_vf_rate,
        .ndo_set_vf_spoofchk    = mlx4_en_set_vf_spoofchk,
        .ndo_set_vf_link_state  = mlx4_en_set_vf_link_state,
        .ndo_get_vf_config      = mlx4_en_get_vf_config,
@@ -2442,6 +2508,7 @@ static const struct net_device_ops mlx4_netdev_ops_master = {
        .ndo_del_vxlan_port     = mlx4_en_del_vxlan_port,
        .ndo_features_check     = mlx4_en_features_check,
 #endif
+       .ndo_set_tx_maxrate     = mlx4_en_set_tx_maxrate,
 };
 
 struct mlx4_en_bond {
@@ -2618,6 +2685,82 @@ int mlx4_en_netdev_event(struct notifier_block *this,
        return NOTIFY_DONE;
 }
 
+void mlx4_en_update_pfc_stats_bitmap(struct mlx4_dev *dev,
+                                    struct mlx4_en_stats_bitmap *stats_bitmap,
+                                    u8 rx_ppp, u8 rx_pause,
+                                    u8 tx_ppp, u8 tx_pause)
+{
+       int last_i = NUM_MAIN_STATS + NUM_PORT_STATS;
+
+       if (!mlx4_is_slave(dev) &&
+           (dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_FLOWSTATS_EN)) {
+               mutex_lock(&stats_bitmap->mutex);
+               bitmap_clear(stats_bitmap->bitmap, last_i, NUM_FLOW_STATS);
+
+               if (rx_ppp)
+                       bitmap_set(stats_bitmap->bitmap, last_i,
+                                  NUM_FLOW_PRIORITY_STATS_RX);
+               last_i += NUM_FLOW_PRIORITY_STATS_RX;
+
+               if (rx_pause && !(rx_ppp))
+                       bitmap_set(stats_bitmap->bitmap, last_i,
+                                  NUM_FLOW_STATS_RX);
+               last_i += NUM_FLOW_STATS_RX;
+
+               if (tx_ppp)
+                       bitmap_set(stats_bitmap->bitmap, last_i,
+                                  NUM_FLOW_PRIORITY_STATS_TX);
+               last_i += NUM_FLOW_PRIORITY_STATS_TX;
+
+               if (tx_pause && !(tx_ppp))
+                       bitmap_set(stats_bitmap->bitmap, last_i,
+                                  NUM_FLOW_STATS_TX);
+               last_i += NUM_FLOW_STATS_TX;
+
+               mutex_unlock(&stats_bitmap->mutex);
+       }
+}
+
+void mlx4_en_set_stats_bitmap(struct mlx4_dev *dev,
+                             struct mlx4_en_stats_bitmap *stats_bitmap,
+                             u8 rx_ppp, u8 rx_pause,
+                             u8 tx_ppp, u8 tx_pause)
+{
+       int last_i = 0;
+
+       mutex_init(&stats_bitmap->mutex);
+       bitmap_zero(stats_bitmap->bitmap, NUM_ALL_STATS);
+
+       if (mlx4_is_slave(dev)) {
+               bitmap_set(stats_bitmap->bitmap, last_i +
+                                        MLX4_FIND_NETDEV_STAT(rx_packets), 1);
+               bitmap_set(stats_bitmap->bitmap, last_i +
+                                        MLX4_FIND_NETDEV_STAT(tx_packets), 1);
+               bitmap_set(stats_bitmap->bitmap, last_i +
+                                        MLX4_FIND_NETDEV_STAT(rx_bytes), 1);
+               bitmap_set(stats_bitmap->bitmap, last_i +
+                                        MLX4_FIND_NETDEV_STAT(tx_bytes), 1);
+               bitmap_set(stats_bitmap->bitmap, last_i +
+                                        MLX4_FIND_NETDEV_STAT(rx_dropped), 1);
+               bitmap_set(stats_bitmap->bitmap, last_i +
+                                        MLX4_FIND_NETDEV_STAT(tx_dropped), 1);
+       } else {
+               bitmap_set(stats_bitmap->bitmap, last_i, NUM_MAIN_STATS);
+       }
+       last_i += NUM_MAIN_STATS;
+
+       bitmap_set(stats_bitmap->bitmap, last_i, NUM_PORT_STATS);
+       last_i += NUM_PORT_STATS;
+
+       mlx4_en_update_pfc_stats_bitmap(dev, stats_bitmap,
+                                       rx_ppp, rx_pause,
+                                       tx_ppp, tx_pause);
+       last_i += NUM_FLOW_STATS;
+
+       if (!mlx4_is_slave(dev))
+               bitmap_set(stats_bitmap->bitmap, last_i, NUM_PKT_STATS);
+}
+
 int mlx4_en_init_netdev(struct mlx4_en_dev *mdev, int port,
                        struct mlx4_en_port_profile *prof)
 {
@@ -2693,7 +2836,7 @@ int mlx4_en_init_netdev(struct mlx4_en_dev *mdev, int port,
        priv->msg_enable = MLX4_EN_MSG_LEVEL;
 #ifdef CONFIG_MLX4_EN_DCB
        if (!mlx4_is_slave(priv->mdev->dev)) {
-               if (mdev->dev->caps.flags & MLX4_DEV_CAP_FLAG_SET_ETH_SCHED) {
+               if (mdev->dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_ETS_CFG) {
                        dev->dcbnl_ops = &mlx4_en_dcbnl_ops;
                } else {
                        en_info(priv, "enabling only PFC DCB ops\n");
@@ -2780,6 +2923,12 @@ int mlx4_en_init_netdev(struct mlx4_en_dev *mdev, int port,
        dev->hw_features |= NETIF_F_LOOPBACK |
                        NETIF_F_HW_VLAN_CTAG_TX | NETIF_F_HW_VLAN_CTAG_RX;
 
+       if (mdev->dev->caps.flags & MLX4_DEV_CAP_FLAG_FCS_KEEP)
+               dev->hw_features |= NETIF_F_RXFCS;
+
+       if (mdev->dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_IGNORE_FCS)
+               dev->hw_features |= NETIF_F_RXALL;
+
        if (mdev->dev->caps.steering_mode ==
            MLX4_STEERING_MODE_DEVICE_MANAGED &&
            mdev->dev->caps.dmfs_high_steer_mode != MLX4_STEERING_DMFS_A0_STATIC)
@@ -2805,13 +2954,6 @@ int mlx4_en_init_netdev(struct mlx4_en_dev *mdev, int port,
        netif_carrier_off(dev);
        mlx4_en_set_default_moderation(priv);
 
-       err = register_netdev(dev);
-       if (err) {
-               en_err(priv, "Netdev registration failed for port %d\n", port);
-               goto out;
-       }
-       priv->registered = 1;
-
        en_warn(priv, "Using %d TX rings\n", prof->tx_ring_num);
        en_warn(priv, "Using %d RX rings\n", prof->rx_ring_num);
 
@@ -2851,7 +2993,19 @@ int mlx4_en_init_netdev(struct mlx4_en_dev *mdev, int port,
                queue_delayed_work(mdev->workqueue, &priv->service_task,
                                   SERVICE_TASK_DELAY);
 
-       mlx4_set_stats_bitmap(mdev->dev, &priv->stats_bitmap);
+       mlx4_en_set_stats_bitmap(mdev->dev, &priv->stats_bitmap,
+                                mdev->profile.prof[priv->port].rx_ppp,
+                                mdev->profile.prof[priv->port].rx_pause,
+                                mdev->profile.prof[priv->port].tx_ppp,
+                                mdev->profile.prof[priv->port].tx_pause);
+
+       err = register_netdev(dev);
+       if (err) {
+               en_err(priv, "Netdev registration failed for port %d\n", port);
+               goto out;
+       }
+
+       priv->registered = 1;
 
        return 0;
 
@@ -2871,7 +3025,8 @@ int mlx4_en_reset_config(struct net_device *dev,
 
        if (priv->hwtstamp_config.tx_type == ts_config.tx_type &&
            priv->hwtstamp_config.rx_filter == ts_config.rx_filter &&
-           !DEV_FEATURE_CHANGED(dev, features, NETIF_F_HW_VLAN_CTAG_RX))
+           !DEV_FEATURE_CHANGED(dev, features, NETIF_F_HW_VLAN_CTAG_RX) &&
+           !DEV_FEATURE_CHANGED(dev, features, NETIF_F_RXFCS))
                return 0; /* Nothing to change */
 
        if (DEV_FEATURE_CHANGED(dev, features, NETIF_F_HW_VLAN_CTAG_RX) &&
@@ -2910,6 +3065,13 @@ int mlx4_en_reset_config(struct net_device *dev,
                        dev->features &= ~NETIF_F_HW_VLAN_CTAG_RX;
        }
 
+       if (DEV_FEATURE_CHANGED(dev, features, NETIF_F_RXFCS)) {
+               if (features & NETIF_F_RXFCS)
+                       dev->features |= NETIF_F_RXFCS;
+               else
+                       dev->features &= ~NETIF_F_RXFCS;
+       }
+
        /* RX vlan offload and RX time-stamping can't co-exist !
         * Regardless of the caller's choice,
         * Turn Off RX vlan offload in case of time-stamping is ON