Merge tag 'rdma-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/roland...
[GitHub/mt8127/android_kernel_alcatel_ttab.git] / drivers / net / ethernet / mellanox / mlx4 / en_netdev.c
index 0860130f2b173a4014a7ec6a24a1183708e61028..b35f9470009363bad560f7142322436baa76d8a3 100644 (file)
@@ -356,7 +356,8 @@ static void mlx4_en_filter_rfs_expire(struct mlx4_en_priv *priv)
 }
 #endif
 
-static int mlx4_en_vlan_rx_add_vid(struct net_device *dev, unsigned short vid)
+static int mlx4_en_vlan_rx_add_vid(struct net_device *dev,
+                                  __be16 proto, u16 vid)
 {
        struct mlx4_en_priv *priv = netdev_priv(dev);
        struct mlx4_en_dev *mdev = priv->mdev;
@@ -381,7 +382,8 @@ static int mlx4_en_vlan_rx_add_vid(struct net_device *dev, unsigned short vid)
        return 0;
 }
 
-static int mlx4_en_vlan_rx_kill_vid(struct net_device *dev, unsigned short vid)
+static int mlx4_en_vlan_rx_kill_vid(struct net_device *dev,
+                                   __be16 proto, u16 vid)
 {
        struct mlx4_en_priv *priv = netdev_priv(dev);
        struct mlx4_en_dev *mdev = priv->mdev;
@@ -1359,6 +1361,27 @@ static void mlx4_en_do_get_stats(struct work_struct *work)
        mutex_unlock(&mdev->state_lock);
 }
 
+/* mlx4_en_service_task - Run service task for tasks that needed to be done
+ * periodically
+ */
+static void mlx4_en_service_task(struct work_struct *work)
+{
+       struct delayed_work *delay = to_delayed_work(work);
+       struct mlx4_en_priv *priv = container_of(delay, struct mlx4_en_priv,
+                                                service_task);
+       struct mlx4_en_dev *mdev = priv->mdev;
+
+       mutex_lock(&mdev->state_lock);
+       if (mdev->device_up) {
+               if (mdev->dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_TS)
+                       mlx4_en_ptp_overflow_check(mdev);
+
+               queue_delayed_work(mdev->workqueue, &priv->service_task,
+                                  SERVICE_TASK_DELAY);
+       }
+       mutex_unlock(&mdev->state_lock);
+}
+
 static void mlx4_en_linkstate(struct work_struct *work)
 {
        struct mlx4_en_priv *priv = container_of(work, struct mlx4_en_priv,
@@ -1863,6 +1886,7 @@ void mlx4_en_destroy_netdev(struct net_device *dev)
                mlx4_free_hwq_res(mdev->dev, &priv->res, MLX4_EN_PAGE_SIZE);
 
        cancel_delayed_work(&priv->stats_task);
+       cancel_delayed_work(&priv->service_task);
        /* flush any pending task for this netdev */
        flush_workqueue(mdev->workqueue);
 
@@ -1914,6 +1938,75 @@ static int mlx4_en_change_mtu(struct net_device *dev, int new_mtu)
        return 0;
 }
 
+static int mlx4_en_hwtstamp_ioctl(struct net_device *dev, struct ifreq *ifr)
+{
+       struct mlx4_en_priv *priv = netdev_priv(dev);
+       struct mlx4_en_dev *mdev = priv->mdev;
+       struct hwtstamp_config config;
+
+       if (copy_from_user(&config, ifr->ifr_data, sizeof(config)))
+               return -EFAULT;
+
+       /* reserved for future extensions */
+       if (config.flags)
+               return -EINVAL;
+
+       /* device doesn't support time stamping */
+       if (!(mdev->dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_TS))
+               return -EINVAL;
+
+       /* TX HW timestamp */
+       switch (config.tx_type) {
+       case HWTSTAMP_TX_OFF:
+       case HWTSTAMP_TX_ON:
+               break;
+       default:
+               return -ERANGE;
+       }
+
+       /* RX HW timestamp */
+       switch (config.rx_filter) {
+       case HWTSTAMP_FILTER_NONE:
+               break;
+       case HWTSTAMP_FILTER_ALL:
+       case HWTSTAMP_FILTER_SOME:
+       case HWTSTAMP_FILTER_PTP_V1_L4_EVENT:
+       case HWTSTAMP_FILTER_PTP_V1_L4_SYNC:
+       case HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ:
+       case HWTSTAMP_FILTER_PTP_V2_L4_EVENT:
+       case HWTSTAMP_FILTER_PTP_V2_L4_SYNC:
+       case HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ:
+       case HWTSTAMP_FILTER_PTP_V2_L2_EVENT:
+       case HWTSTAMP_FILTER_PTP_V2_L2_SYNC:
+       case HWTSTAMP_FILTER_PTP_V2_L2_DELAY_REQ:
+       case HWTSTAMP_FILTER_PTP_V2_EVENT:
+       case HWTSTAMP_FILTER_PTP_V2_SYNC:
+       case HWTSTAMP_FILTER_PTP_V2_DELAY_REQ:
+               config.rx_filter = HWTSTAMP_FILTER_ALL;
+               break;
+       default:
+               return -ERANGE;
+       }
+
+       if (mlx4_en_timestamp_config(dev, config.tx_type, config.rx_filter)) {
+               config.tx_type = HWTSTAMP_TX_OFF;
+               config.rx_filter = HWTSTAMP_FILTER_NONE;
+       }
+
+       return copy_to_user(ifr->ifr_data, &config,
+                           sizeof(config)) ? -EFAULT : 0;
+}
+
+static int mlx4_en_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
+{
+       switch (cmd) {
+       case SIOCSHWTSTAMP:
+               return mlx4_en_hwtstamp_ioctl(dev, ifr);
+       default:
+               return -EOPNOTSUPP;
+       }
+}
+
 static int mlx4_en_set_features(struct net_device *netdev,
                netdev_features_t features)
 {
@@ -1931,77 +2024,40 @@ static int mlx4_en_set_features(struct net_device *netdev,
 
 }
 
-static int mlx4_en_fdb_add(struct ndmsg *ndm, struct nlattr *tb[],
-                          struct net_device *dev,
-                          const unsigned char *addr, u16 flags)
+static int mlx4_en_set_vf_mac(struct net_device *dev, int queue, u8 *mac)
 {
-       struct mlx4_en_priv *priv = netdev_priv(dev);
-       struct mlx4_dev *mdev = priv->mdev->dev;
-       int err;
-
-       if (!mlx4_is_mfunc(mdev))
-               return -EOPNOTSUPP;
+       struct mlx4_en_priv *en_priv = netdev_priv(dev);
+       struct mlx4_en_dev *mdev = en_priv->mdev;
+       u64 mac_u64 = mlx4_en_mac_to_u64(mac);
 
-       /* Hardware does not support aging addresses, allow only
-        * permanent addresses if ndm_state is given
-        */
-       if (ndm->ndm_state && !(ndm->ndm_state & NUD_PERMANENT)) {
-               en_info(priv, "Add FDB only supports static addresses\n");
+       if (!is_valid_ether_addr(mac))
                return -EINVAL;
-       }
 
-       if (is_unicast_ether_addr(addr) || is_link_local_ether_addr(addr))
-               err = dev_uc_add_excl(dev, addr);
-       else if (is_multicast_ether_addr(addr))
-               err = dev_mc_add_excl(dev, addr);
-       else
-               err = -EINVAL;
-
-       /* Only return duplicate errors if NLM_F_EXCL is set */
-       if (err == -EEXIST && !(flags & NLM_F_EXCL))
-               err = 0;
-
-       return err;
+       return mlx4_set_vf_mac(mdev->dev, en_priv->port, queue, mac_u64);
 }
 
-static int mlx4_en_fdb_del(struct ndmsg *ndm,
-                          struct nlattr *tb[],
-                          struct net_device *dev,
-                          const unsigned char *addr)
+static int mlx4_en_set_vf_vlan(struct net_device *dev, int vf, u16 vlan, u8 qos)
 {
-       struct mlx4_en_priv *priv = netdev_priv(dev);
-       struct mlx4_dev *mdev = priv->mdev->dev;
-       int err;
-
-       if (!mlx4_is_mfunc(mdev))
-               return -EOPNOTSUPP;
+       struct mlx4_en_priv *en_priv = netdev_priv(dev);
+       struct mlx4_en_dev *mdev = en_priv->mdev;
 
-       if (ndm->ndm_state && !(ndm->ndm_state & NUD_PERMANENT)) {
-               en_info(priv, "Del FDB only supports static addresses\n");
-               return -EINVAL;
-       }
+       return mlx4_set_vf_vlan(mdev->dev, en_priv->port, vf, vlan, qos);
+}
 
-       if (is_unicast_ether_addr(addr) || is_link_local_ether_addr(addr))
-               err = dev_uc_del(dev, addr);
-       else if (is_multicast_ether_addr(addr))
-               err = dev_mc_del(dev, addr);
-       else
-               err = -EINVAL;
+static int mlx4_en_set_vf_spoofchk(struct net_device *dev, int vf, bool setting)
+{
+       struct mlx4_en_priv *en_priv = netdev_priv(dev);
+       struct mlx4_en_dev *mdev = en_priv->mdev;
 
-       return err;
+       return mlx4_set_vf_spoofchk(mdev->dev, en_priv->port, vf, setting);
 }
 
-static int mlx4_en_fdb_dump(struct sk_buff *skb,
-                           struct netlink_callback *cb,
-                           struct net_device *dev, int idx)
+static int mlx4_en_get_vf_config(struct net_device *dev, int vf, struct ifla_vf_info *ivf)
 {
-       struct mlx4_en_priv *priv = netdev_priv(dev);
-       struct mlx4_dev *mdev = priv->mdev->dev;
-
-       if (mlx4_is_mfunc(mdev))
-               idx = ndo_dflt_fdb_dump(skb, cb, dev, idx);
+       struct mlx4_en_priv *en_priv = netdev_priv(dev);
+       struct mlx4_en_dev *mdev = en_priv->mdev;
 
-       return idx;
+       return mlx4_get_vf_config(mdev->dev, en_priv->port, vf, ivf);
 }
 
 static const struct net_device_ops mlx4_netdev_ops = {
@@ -2014,6 +2070,7 @@ static const struct net_device_ops mlx4_netdev_ops = {
        .ndo_set_mac_address    = mlx4_en_set_mac,
        .ndo_validate_addr      = eth_validate_addr,
        .ndo_change_mtu         = mlx4_en_change_mtu,
+       .ndo_do_ioctl           = mlx4_en_ioctl,
        .ndo_tx_timeout         = mlx4_en_tx_timeout,
        .ndo_vlan_rx_add_vid    = mlx4_en_vlan_rx_add_vid,
        .ndo_vlan_rx_kill_vid   = mlx4_en_vlan_rx_kill_vid,
@@ -2025,9 +2082,33 @@ static const struct net_device_ops mlx4_netdev_ops = {
 #ifdef CONFIG_RFS_ACCEL
        .ndo_rx_flow_steer      = mlx4_en_filter_rfs,
 #endif
-       .ndo_fdb_add            = mlx4_en_fdb_add,
-       .ndo_fdb_del            = mlx4_en_fdb_del,
-       .ndo_fdb_dump           = mlx4_en_fdb_dump,
+};
+
+static const struct net_device_ops mlx4_netdev_ops_master = {
+       .ndo_open               = mlx4_en_open,
+       .ndo_stop               = mlx4_en_close,
+       .ndo_start_xmit         = mlx4_en_xmit,
+       .ndo_select_queue       = mlx4_en_select_queue,
+       .ndo_get_stats          = mlx4_en_get_stats,
+       .ndo_set_rx_mode        = mlx4_en_set_rx_mode,
+       .ndo_set_mac_address    = mlx4_en_set_mac,
+       .ndo_validate_addr      = eth_validate_addr,
+       .ndo_change_mtu         = mlx4_en_change_mtu,
+       .ndo_tx_timeout         = mlx4_en_tx_timeout,
+       .ndo_vlan_rx_add_vid    = mlx4_en_vlan_rx_add_vid,
+       .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_spoofchk    = mlx4_en_set_vf_spoofchk,
+       .ndo_get_vf_config      = mlx4_en_get_vf_config,
+#ifdef CONFIG_NET_POLL_CONTROLLER
+       .ndo_poll_controller    = mlx4_en_netpoll,
+#endif
+       .ndo_set_features       = mlx4_en_set_features,
+       .ndo_setup_tc           = mlx4_en_setup_tc,
+#ifdef CONFIG_RFS_ACCEL
+       .ndo_rx_flow_steer      = mlx4_en_filter_rfs,
+#endif
 };
 
 int mlx4_en_init_netdev(struct mlx4_en_dev *mdev, int port,
@@ -2088,9 +2169,16 @@ int mlx4_en_init_netdev(struct mlx4_en_dev *mdev, int port,
        INIT_WORK(&priv->watchdog_task, mlx4_en_restart);
        INIT_WORK(&priv->linkstate_task, mlx4_en_linkstate);
        INIT_DELAYED_WORK(&priv->stats_task, mlx4_en_do_get_stats);
+       INIT_DELAYED_WORK(&priv->service_task, mlx4_en_service_task);
 #ifdef CONFIG_MLX4_EN_DCB
-       if (!mlx4_is_slave(priv->mdev->dev))
-               dev->dcbnl_ops = &mlx4_en_dcbnl_ops;
+       if (!mlx4_is_slave(priv->mdev->dev)) {
+               if (mdev->dev->caps.flags & MLX4_DEV_CAP_FLAG_SET_ETH_SCHED) {
+                       dev->dcbnl_ops = &mlx4_en_dcbnl_ops;
+               } else {
+                       en_info(priv, "enabling only PFC DCB ops\n");
+                       dev->dcbnl_ops = &mlx4_en_dcbnl_pfc_ops;
+               }
+       }
 #endif
 
        for (i = 0; i < MLX4_EN_MAC_HASH_SIZE; ++i)
@@ -2122,6 +2210,11 @@ int mlx4_en_init_netdev(struct mlx4_en_dev *mdev, int port,
        spin_lock_init(&priv->filters_lock);
 #endif
 
+       /* Initialize time stamping config */
+       priv->hwtstamp_config.flags = 0;
+       priv->hwtstamp_config.tx_type = HWTSTAMP_TX_OFF;
+       priv->hwtstamp_config.rx_filter = HWTSTAMP_FILTER_NONE;
+
        /* Allocate page for receive rings */
        err = mlx4_alloc_hwq_res(mdev->dev, &priv->res,
                                MLX4_EN_PAGE_SIZE, MLX4_EN_PAGE_SIZE);
@@ -2134,7 +2227,10 @@ int mlx4_en_init_netdev(struct mlx4_en_dev *mdev, int port,
        /*
         * Initialize netdev entry points
         */
-       dev->netdev_ops = &mlx4_netdev_ops;
+       if (mlx4_is_master(priv->mdev->dev))
+               dev->netdev_ops = &mlx4_netdev_ops_master;
+       else
+               dev->netdev_ops = &mlx4_netdev_ops;
        dev->watchdog_timeo = MLX4_EN_WATCHDOG_TIMEOUT;
        netif_set_real_num_tx_queues(dev, priv->tx_ring_num);
        netif_set_real_num_rx_queues(dev, priv->rx_ring_num);
@@ -2152,8 +2248,8 @@ int mlx4_en_init_netdev(struct mlx4_en_dev *mdev, int port,
 
        dev->hw_features |= NETIF_F_RXCSUM | NETIF_F_RXHASH;
        dev->features = dev->hw_features | NETIF_F_HIGHDMA |
-                       NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX |
-                       NETIF_F_HW_VLAN_FILTER;
+                       NETIF_F_HW_VLAN_CTAG_TX | NETIF_F_HW_VLAN_CTAG_RX |
+                       NETIF_F_HW_VLAN_CTAG_FILTER;
        dev->hw_features |= NETIF_F_LOOPBACK;
 
        if (mdev->dev->caps.steering_mode ==
@@ -2199,6 +2295,11 @@ int mlx4_en_init_netdev(struct mlx4_en_dev *mdev, int port,
        }
        mlx4_en_set_default_moderation(priv);
        queue_delayed_work(mdev->workqueue, &priv->stats_task, STATS_DELAY);
+
+       if (mdev->dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_TS)
+               queue_delayed_work(mdev->workqueue, &priv->service_task,
+                                  SERVICE_TASK_DELAY);
+
        return 0;
 
 out: