The drop action is implemented by allocating a QP and keeping it in a reset state
such that the HW drops any packets which are steered to that QP. When a drop action
is requested, we attach the relevant flow to that QP.
Sign-off-by: Hadar Hen Zion <hadarh@mellanox.co.il>
Signed-off-by: Or Gerlitz <ogerlitz@mellanox.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
 
        /* Allow direct QP attaches if the EN_ETHTOOL_QP_ATTACH flag is set */
        if (cmd->fs.ring_cookie == RX_CLS_FLOW_DISC)
-               return -EINVAL;
+               qpn = priv->drop_qp.qpn;
        else if (cmd->fs.ring_cookie & EN_ETHTOOL_QP_ATTACH) {
                qpn = cmd->fs.ring_cookie & (EN_ETHTOOL_QP_ATTACH - 1);
        } else {
 
                goto mac_err;
        }
 
+       err = mlx4_en_create_drop_qp(priv);
+       if (err)
+               goto rss_err;
+
        /* Configure tx cq's and rings */
        for (i = 0; i < priv->tx_ring_num; i++) {
                /* Configure cq */
                mlx4_en_deactivate_tx_ring(priv, &priv->tx_ring[tx_index]);
                mlx4_en_deactivate_cq(priv, &priv->tx_cq[tx_index]);
        }
-
+       mlx4_en_destroy_drop_qp(priv);
+rss_err:
        mlx4_en_release_rss_steer(priv);
 mac_err:
        mlx4_put_eth_qp(mdev->dev, priv->port, priv->mac, priv->base_qpn);
        /* Flush multicast filter */
        mlx4_SET_MCAST_FLTR(mdev->dev, priv->port, 0, 1, MLX4_MCAST_CONFIG);
 
+       mlx4_en_destroy_drop_qp(priv);
+
        /* Free TX Rings */
        for (i = 0; i < priv->tx_ring_num; i++) {
                mlx4_en_deactivate_tx_ring(priv, &priv->tx_ring[i]);
 
        return err;
 }
 
+int mlx4_en_create_drop_qp(struct mlx4_en_priv *priv)
+{
+       int err;
+       u32 qpn;
+
+       err = mlx4_qp_reserve_range(priv->mdev->dev, 1, 1, &qpn);
+       if (err) {
+               en_err(priv, "Failed reserving drop qpn\n");
+               return err;
+       }
+       err = mlx4_qp_alloc(priv->mdev->dev, qpn, &priv->drop_qp);
+       if (err) {
+               en_err(priv, "Failed allocating drop qp\n");
+               mlx4_qp_release_range(priv->mdev->dev, qpn, 1);
+               return err;
+       }
+
+       return 0;
+}
+
+void mlx4_en_destroy_drop_qp(struct mlx4_en_priv *priv)
+{
+       u32 qpn;
+
+       qpn = priv->drop_qp.qpn;
+       mlx4_qp_remove(priv->mdev->dev, &priv->drop_qp);
+       mlx4_qp_free(priv->mdev->dev, &priv->drop_qp);
+       mlx4_qp_release_range(priv->mdev->dev, qpn, 1);
+}
+
 /* Allocate rx qp's and configure them according to rss map */
 int mlx4_en_config_rss_steer(struct mlx4_en_priv *priv)
 {
 
        struct mlx4_en_rx_ring rx_ring[MAX_RX_RINGS];
        struct mlx4_en_cq *tx_cq;
        struct mlx4_en_cq rx_cq[MAX_RX_RINGS];
+       struct mlx4_qp drop_qp;
        struct work_struct mcast_task;
        struct work_struct mac_task;
        struct work_struct watchdog_task;
 void mlx4_en_calc_rx_buf(struct net_device *dev);
 int mlx4_en_config_rss_steer(struct mlx4_en_priv *priv);
 void mlx4_en_release_rss_steer(struct mlx4_en_priv *priv);
+int mlx4_en_create_drop_qp(struct mlx4_en_priv *priv);
+void mlx4_en_destroy_drop_qp(struct mlx4_en_priv *priv);
 int mlx4_en_free_tx_buf(struct net_device *dev, struct mlx4_en_tx_ring *ring);
 void mlx4_en_rx_irq(struct mlx4_cq *mcq);