ethdev: use constants for link state
[dpdk.git] / drivers / net / ixgbe / ixgbe_ethdev.c
index 9a392b9..8bcd0d8 100644 (file)
@@ -1,7 +1,7 @@
 /*-
  *   BSD LICENSE
  *
- *   Copyright(c) 2010-2015 Intel Corporation. All rights reserved.
+ *   Copyright(c) 2010-2016 Intel Corporation. All rights reserved.
  *   All rights reserved.
  *
  *   Redistribution and use in source and binary forms, with or without
 #define IXGBE_VMTIR(_i) (0x00017000 + ((_i) * 4)) /* 64 of these (0-63) */
 #define IXGBE_QDE_STRIP_TAG                    0x00000004
 
+enum ixgbevf_xcast_modes {
+       IXGBEVF_XCAST_MODE_NONE = 0,
+       IXGBEVF_XCAST_MODE_MULTI,
+       IXGBEVF_XCAST_MODE_ALLMULTI,
+};
+
 static int eth_ixgbe_dev_init(struct rte_eth_dev *eth_dev);
 static int eth_ixgbe_dev_uninit(struct rte_eth_dev *eth_dev);
 static int  ixgbe_dev_configure(struct rte_eth_dev *dev);
@@ -179,6 +185,7 @@ static int ixgbe_dev_queue_stats_mapping_set(struct rte_eth_dev *eth_dev,
                                             uint8_t is_rx);
 static void ixgbe_dev_info_get(struct rte_eth_dev *dev,
                               struct rte_eth_dev_info *dev_info);
+static const uint32_t *ixgbe_dev_supported_ptypes_get(struct rte_eth_dev *dev);
 static void ixgbevf_dev_info_get(struct rte_eth_dev *dev,
                                 struct rte_eth_dev_info *dev_info);
 static int ixgbe_dev_mtu_set(struct rte_eth_dev *dev, uint16_t mtu);
@@ -252,6 +259,8 @@ static int ixgbevf_dev_rx_queue_intr_disable(struct rte_eth_dev *dev,
 static void ixgbevf_set_ivar_map(struct ixgbe_hw *hw, int8_t direction,
                                 uint8_t queue, uint8_t msix_vector);
 static void ixgbevf_configure_msix(struct rte_eth_dev *dev);
+static void ixgbevf_dev_allmulticast_enable(struct rte_eth_dev *dev);
+static void ixgbevf_dev_allmulticast_disable(struct rte_eth_dev *dev);
 
 /* For Eth VMDQ APIs support */
 static int ixgbe_uc_hash_table_set(struct rte_eth_dev *dev, struct
@@ -459,6 +468,7 @@ static const struct eth_dev_ops ixgbe_eth_dev_ops = {
        .xstats_reset         = ixgbe_dev_xstats_reset,
        .queue_stats_mapping_set = ixgbe_dev_queue_stats_mapping_set,
        .dev_infos_get        = ixgbe_dev_info_get,
+       .dev_supported_ptypes_get = ixgbe_dev_supported_ptypes_get,
        .mtu_set              = ixgbe_dev_mtu_set,
        .vlan_filter_set      = ixgbe_vlan_filter_set,
        .vlan_tpid_set        = ixgbe_vlan_tpid_set,
@@ -546,7 +556,10 @@ static const struct eth_dev_ops ixgbevf_eth_dev_ops = {
        .stats_reset          = ixgbevf_dev_stats_reset,
        .xstats_reset         = ixgbevf_dev_stats_reset,
        .dev_close            = ixgbevf_dev_close,
+       .allmulticast_enable  = ixgbevf_dev_allmulticast_enable,
+       .allmulticast_disable = ixgbevf_dev_allmulticast_disable,
        .dev_infos_get        = ixgbevf_dev_info_get,
+       .dev_supported_ptypes_get = ixgbe_dev_supported_ptypes_get,
        .mtu_set              = ixgbevf_dev_set_mtu,
        .vlan_filter_set      = ixgbevf_vlan_filter_set,
        .vlan_strip_queue_set = ixgbevf_vlan_strip_queue_set,
@@ -847,7 +860,8 @@ ixgbe_dev_queue_stats_mapping_set(struct rte_eth_dev *eth_dev,
        if ((hw->mac.type != ixgbe_mac_82599EB) &&
                (hw->mac.type != ixgbe_mac_X540) &&
                (hw->mac.type != ixgbe_mac_X550) &&
-               (hw->mac.type != ixgbe_mac_X550EM_x))
+               (hw->mac.type != ixgbe_mac_X550EM_x) &&
+               (hw->mac.type != ixgbe_mac_X550EM_a))
                return -ENOSYS;
 
        PMD_INIT_LOG(DEBUG, "Setting port %d, %s queue_id %d to stat index %d",
@@ -952,7 +966,8 @@ ixgbe_dcb_init(struct ixgbe_hw *hw,struct ixgbe_dcb_config *dcb_config)
        /*we only support 4 Tcs for X540, X550 */
        if (hw->mac.type == ixgbe_mac_X540 ||
                hw->mac.type == ixgbe_mac_X550 ||
-               hw->mac.type == ixgbe_mac_X550EM_x) {
+               hw->mac.type == ixgbe_mac_X550EM_x ||
+               hw->mac.type == ixgbe_mac_X550EM_a) {
                dcb_config->num_tcs.pg_tcs = 4;
                dcb_config->num_tcs.pfc_tcs = 4;
        }
@@ -1259,6 +1274,7 @@ ixgbevf_negotiate_api(struct ixgbe_hw *hw)
 
        /* start with highest supported, proceed down */
        static const enum ixgbe_pfvf_api_rev sup_ver[] = {
+               ixgbe_mbox_api_12,
                ixgbe_mbox_api_11,
                ixgbe_mbox_api_10,
        };
@@ -1313,8 +1329,21 @@ eth_ixgbevf_dev_init(struct rte_eth_dev *eth_dev)
         * has already done this work. Only check we don't need a different
         * RX function */
        if (rte_eal_process_type() != RTE_PROC_PRIMARY){
-               if (eth_dev->data->scattered_rx)
-                       eth_dev->rx_pkt_burst = ixgbe_recv_pkts_lro_single_alloc;
+               struct ixgbe_tx_queue *txq;
+               /* TX queue function in primary, set by last queue initialized
+                * Tx queue may not initialized by primary process
+                */
+               if (eth_dev->data->tx_queues) {
+                       txq = eth_dev->data->tx_queues[eth_dev->data->nb_tx_queues - 1];
+                       ixgbe_set_tx_function(eth_dev, txq);
+               } else {
+                       /* Use default TX function if we get here */
+                       PMD_INIT_LOG(NOTICE,
+                               "No TX queues configured yet. Using default TX function.");
+               }
+
+               ixgbe_set_rx_function(eth_dev);
+
                return 0;
        }
 
@@ -1425,7 +1454,6 @@ static int
 eth_ixgbevf_dev_uninit(struct rte_eth_dev *eth_dev)
 {
        struct ixgbe_hw *hw;
-       unsigned i;
 
        PMD_INIT_FUNC_TRACE();
 
@@ -1444,18 +1472,6 @@ eth_ixgbevf_dev_uninit(struct rte_eth_dev *eth_dev)
        /* Disable the interrupts for VF */
        ixgbevf_intr_disable(hw);
 
-       for (i = 0; i < eth_dev->data->nb_rx_queues; i++) {
-               ixgbe_dev_rx_queue_release(eth_dev->data->rx_queues[i]);
-               eth_dev->data->rx_queues[i] = NULL;
-       }
-       eth_dev->data->nb_rx_queues = 0;
-
-       for (i = 0; i < eth_dev->data->nb_tx_queues; i++) {
-               ixgbe_dev_tx_queue_release(eth_dev->data->tx_queues[i]);
-               eth_dev->data->tx_queues[i] = NULL;
-       }
-       eth_dev->data->nb_tx_queues = 0;
-
        rte_free(eth_dev->data->mac_addrs);
        eth_dev->data->mac_addrs = NULL;
 
@@ -1775,7 +1791,8 @@ ixgbe_vlan_hw_extend_enable(struct rte_eth_dev *dev)
 
        /* Clear pooling mode of PFVTCTL. It's required by X550. */
        if (hw->mac.type == ixgbe_mac_X550 ||
-           hw->mac.type == ixgbe_mac_X550EM_x) {
+           hw->mac.type == ixgbe_mac_X550EM_x ||
+           hw->mac.type == ixgbe_mac_X550EM_a) {
                ctrl = IXGBE_READ_REG(hw, IXGBE_VT_CTL);
                ctrl &= ~IXGBE_VT_CTL_POOLING_MODE_MASK;
                IXGBE_WRITE_REG(hw, IXGBE_VT_CTL, ctrl);
@@ -1848,8 +1865,9 @@ static int
 ixgbe_check_mq_mode(struct rte_eth_dev *dev)
 {
        struct rte_eth_conf *dev_conf = &dev->data->dev_conf;
+       struct ixgbe_hw *hw = IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private);
        uint16_t nb_rx_q = dev->data->nb_rx_queues;
-       uint16_t nb_tx_q = dev->data->nb_rx_queues;
+       uint16_t nb_tx_q = dev->data->nb_tx_queues;
 
        if (RTE_ETH_DEV_SRIOV(dev).active != 0) {
                /* check multi-queue mode */
@@ -1904,11 +1922,18 @@ ixgbe_check_mq_mode(struct rte_eth_dev *dev)
                if ((nb_rx_q > RTE_ETH_DEV_SRIOV(dev).nb_q_per_pool) ||
                    (nb_tx_q > RTE_ETH_DEV_SRIOV(dev).nb_q_per_pool)) {
                        PMD_INIT_LOG(ERR, "SRIOV is active,"
-                                       " queue number must less equal to %d.",
+                                       " nb_rx_q=%d nb_tx_q=%d queue number"
+                                       " must be less than or equal to %d.",
+                                       nb_rx_q, nb_tx_q,
                                        RTE_ETH_DEV_SRIOV(dev).nb_q_per_pool);
                        return -EINVAL;
                }
        } else {
+               if (dev_conf->rxmode.mq_mode == ETH_MQ_RX_VMDQ_DCB_RSS) {
+                       PMD_INIT_LOG(ERR, "VMDQ+DCB+RSS mq_mode is"
+                                         " not supported.");
+                       return -EINVAL;
+               }
                /* check configuration for vmdb+dcb mode */
                if (dev_conf->rxmode.mq_mode == ETH_MQ_RX_VMDQ_DCB) {
                        const struct rte_eth_vmdq_dcb_conf *conf;
@@ -1982,6 +2007,21 @@ ixgbe_check_mq_mode(struct rte_eth_dev *dev)
                                return -EINVAL;
                        }
                }
+
+               /*
+                * When DCB/VT is off, maximum number of queues changes,
+                * except for 82598EB, which remains constant.
+                */
+               if (dev_conf->txmode.mq_mode == ETH_MQ_TX_NONE &&
+                               hw->mac.type != ixgbe_mac_82598EB) {
+                       if (nb_tx_q > IXGBE_NONE_MODE_TX_NB_QUEUES) {
+                               PMD_INIT_LOG(ERR,
+                                            "Neither VT nor DCB are enabled, "
+                                            "nb_tx_q > %d.",
+                                            IXGBE_NONE_MODE_TX_NB_QUEUES);
+                               return -EINVAL;
+                       }
+               }
        }
        return 0;
 }
@@ -2017,6 +2057,25 @@ ixgbe_dev_configure(struct rte_eth_dev *dev)
        return 0;
 }
 
+static void
+ixgbe_dev_phy_intr_setup(struct rte_eth_dev *dev)
+{
+       struct ixgbe_hw *hw =
+               IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+       struct ixgbe_interrupt *intr =
+               IXGBE_DEV_PRIVATE_TO_INTR(dev->data->dev_private);
+       uint32_t gpie;
+
+       /* only set up it on X550EM_X */
+       if (hw->mac.type == ixgbe_mac_X550EM_x) {
+               gpie = IXGBE_READ_REG(hw, IXGBE_GPIE);
+               gpie |= IXGBE_SDP0_GPIEN_X550EM_x;
+               IXGBE_WRITE_REG(hw, IXGBE_GPIE, gpie);
+               if (hw->phy.type == ixgbe_phy_x550em_ext_t)
+                       intr->mask |= IXGBE_EICR_GPI_SDP0_X550EM_x;
+       }
+}
+
 /*
  * Configure device link speed and setup link.
  * It returns 0 on success.
@@ -2065,11 +2124,18 @@ ixgbe_dev_start(struct rte_eth_dev *dev)
        /* configure PF module if SRIOV enabled */
        ixgbe_pf_host_configure(dev);
 
+       ixgbe_dev_phy_intr_setup(dev);
+
        /* check and configure queue intr-vector mapping */
        if ((rte_intr_cap_multiple(intr_handle) ||
             !RTE_ETH_DEV_SRIOV(dev).active) &&
            dev->data->dev_conf.intr_conf.rxq != 0) {
                intr_vector = dev->data->nb_rx_queues;
+               if (intr_vector > IXGBE_MAX_INTR_QUEUE_NUM) {
+                       PMD_INIT_LOG(ERR, "At most %d intr queues supported",
+                                       IXGBE_MAX_INTR_QUEUE_NUM);
+                       return -ENOTSUP;
+               }
                if (rte_intr_efd_enable(intr_handle, intr_vector))
                        return -1;
        }
@@ -2248,9 +2314,6 @@ ixgbe_dev_stop(struct rte_eth_dev *dev)
        /* disable interrupts */
        ixgbe_disable_intr(hw);
 
-       /* disable intr eventfd mapping */
-       rte_intr_disable(intr_handle);
-
        /* reset the NIC */
        ixgbe_pf_reset_hw(hw);
        hw->adapter_stopped = 0;
@@ -2608,7 +2671,6 @@ ixgbe_dev_stats_get(struct rte_eth_dev *dev, struct rte_eth_stats *stats)
                          hw_stats->rlec +
                          hw_stats->ruc +
                          hw_stats->roc +
-                         total_missed_rx +
                          hw_stats->illerrc +
                          hw_stats->errbc +
                          hw_stats->rfc +
@@ -2819,9 +2881,19 @@ static void
 ixgbe_dev_info_get(struct rte_eth_dev *dev, struct rte_eth_dev_info *dev_info)
 {
        struct ixgbe_hw *hw = IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+       struct rte_eth_conf *dev_conf = &dev->data->dev_conf;
 
        dev_info->max_rx_queues = (uint16_t)hw->mac.max_rx_queues;
        dev_info->max_tx_queues = (uint16_t)hw->mac.max_tx_queues;
+       if (RTE_ETH_DEV_SRIOV(dev).active == 0) {
+               /*
+                * When DCB/VT is off, maximum number of queues changes,
+                * except for 82598EB, which remains constant.
+                */
+               if (dev_conf->txmode.mq_mode == ETH_MQ_TX_NONE &&
+                               hw->mac.type != ixgbe_mac_82598EB)
+                       dev_info->max_tx_queues = IXGBE_NONE_MODE_TX_NB_QUEUES;
+       }
        dev_info->min_rx_bufsize = 1024; /* cf BSIZEPACKET in SRRCTL register */
        dev_info->max_rx_pktlen = 15872; /* includes CRC, cf MAXFRS register */
        dev_info->max_mac_addrs = hw->mac.num_rar_entries;
@@ -2848,7 +2920,8 @@ ixgbe_dev_info_get(struct rte_eth_dev *dev, struct rte_eth_dev_info *dev_info)
                dev_info->rx_offload_capa |= DEV_RX_OFFLOAD_TCP_LRO;
 
        if (hw->mac.type == ixgbe_mac_X550 ||
-           hw->mac.type == ixgbe_mac_X550EM_x)
+           hw->mac.type == ixgbe_mac_X550EM_x ||
+           hw->mac.type == ixgbe_mac_X550EM_a)
                dev_info->rx_offload_capa |= DEV_RX_OFFLOAD_OUTER_IPV4_CKSUM;
 
        dev_info->tx_offload_capa =
@@ -2860,7 +2933,8 @@ ixgbe_dev_info_get(struct rte_eth_dev *dev, struct rte_eth_dev_info *dev_info)
                DEV_TX_OFFLOAD_TCP_TSO;
 
        if (hw->mac.type == ixgbe_mac_X550 ||
-           hw->mac.type == ixgbe_mac_X550EM_x)
+           hw->mac.type == ixgbe_mac_X550EM_x ||
+           hw->mac.type == ixgbe_mac_X550EM_a)
                dev_info->tx_offload_capa |= DEV_TX_OFFLOAD_OUTER_IPV4_CKSUM;
 
        dev_info->default_rxconf = (struct rte_eth_rxconf) {
@@ -2893,6 +2967,39 @@ ixgbe_dev_info_get(struct rte_eth_dev *dev, struct rte_eth_dev_info *dev_info)
        dev_info->flow_type_rss_offloads = IXGBE_RSS_OFFLOAD_ALL;
 }
 
+static const uint32_t *
+ixgbe_dev_supported_ptypes_get(struct rte_eth_dev *dev)
+{
+       static const uint32_t ptypes[] = {
+               /* For non-vec functions,
+                * refers to ixgbe_rxd_pkt_info_to_pkt_type();
+                * for vec functions,
+                * refers to _recv_raw_pkts_vec().
+                */
+               RTE_PTYPE_L2_ETHER,
+               RTE_PTYPE_L3_IPV4,
+               RTE_PTYPE_L3_IPV4_EXT,
+               RTE_PTYPE_L3_IPV6,
+               RTE_PTYPE_L3_IPV6_EXT,
+               RTE_PTYPE_L4_SCTP,
+               RTE_PTYPE_L4_TCP,
+               RTE_PTYPE_L4_UDP,
+               RTE_PTYPE_TUNNEL_IP,
+               RTE_PTYPE_INNER_L3_IPV6,
+               RTE_PTYPE_INNER_L3_IPV6_EXT,
+               RTE_PTYPE_INNER_L4_TCP,
+               RTE_PTYPE_INNER_L4_UDP,
+               RTE_PTYPE_UNKNOWN
+       };
+
+       if (dev->rx_pkt_burst == ixgbe_recv_pkts ||
+           dev->rx_pkt_burst == ixgbe_recv_pkts_lro_single_alloc ||
+           dev->rx_pkt_burst == ixgbe_recv_pkts_lro_bulk_alloc ||
+           dev->rx_pkt_burst == ixgbe_recv_pkts_bulk_alloc)
+               return ptypes;
+       return NULL;
+}
+
 static void
 ixgbevf_dev_info_get(struct rte_eth_dev *dev,
                     struct rte_eth_dev_info *dev_info)
@@ -2957,7 +3064,7 @@ ixgbe_dev_link_update(struct rte_eth_dev *dev, int wait_to_complete)
        int link_up;
        int diag;
 
-       link.link_status = 0;
+       link.link_status = ETH_LINK_DOWN;
        link.link_speed = 0;
        link.link_duplex = 0;
        memset(&old, 0, sizeof(old));
@@ -2986,7 +3093,7 @@ ixgbe_dev_link_update(struct rte_eth_dev *dev, int wait_to_complete)
                        return -1;
                return 0;
        }
-       link.link_status = 1;
+       link.link_status = ETH_LINK_UP;
        link.link_duplex = ETH_LINK_FULL_DUPLEX;
 
        switch (link_speed) {
@@ -3146,6 +3253,11 @@ ixgbe_dev_interrupt_get_status(struct rte_eth_dev *dev)
        if (eicr & IXGBE_EICR_MAILBOX)
                intr->flags |= IXGBE_FLAG_MAILBOX;
 
+       if (hw->mac.type ==  ixgbe_mac_X550EM_x &&
+           hw->phy.type == ixgbe_phy_x550em_ext_t &&
+           (eicr & IXGBE_EICR_GPI_SDP0_X550EM_x))
+               intr->flags |= IXGBE_FLAG_PHY_INTERRUPT;
+
        return 0;
 }
 
@@ -3201,6 +3313,8 @@ ixgbe_dev_interrupt_action(struct rte_eth_dev *dev)
        int64_t timeout;
        struct rte_eth_link link;
        int intr_enable_delay = false;
+       struct ixgbe_hw *hw =
+               IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private);
 
        PMD_DRV_LOG(DEBUG, "intr action type %d", intr->flags);
 
@@ -3209,6 +3323,11 @@ ixgbe_dev_interrupt_action(struct rte_eth_dev *dev)
                intr->flags &= ~IXGBE_FLAG_MAILBOX;
        }
 
+       if (intr->flags & IXGBE_FLAG_PHY_INTERRUPT) {
+               ixgbe_handle_lasi(hw);
+               intr->flags &= ~IXGBE_FLAG_PHY_INTERRUPT;
+       }
+
        if (intr->flags & IXGBE_FLAG_NEED_LINK_UPDATE) {
                /* get the link status before link update, for predicting later */
                memset(&link, 0, sizeof(link));
@@ -3272,6 +3391,11 @@ ixgbe_dev_interrupt_delayed_handler(void *param)
        if (eicr & IXGBE_EICR_MAILBOX)
                ixgbe_pf_mbx_process(dev);
 
+       if (intr->flags & IXGBE_FLAG_PHY_INTERRUPT) {
+               ixgbe_handle_lasi(hw);
+               intr->flags &= ~IXGBE_FLAG_PHY_INTERRUPT;
+       }
+
        if (intr->flags & IXGBE_FLAG_NEED_LINK_UPDATE) {
                ixgbe_dev_link_update(dev, 0);
                intr->flags &= ~IXGBE_FLAG_NEED_LINK_UPDATE;
@@ -3649,11 +3773,11 @@ ixgbe_dev_rss_reta_update(struct rte_eth_dev *dev,
                          struct rte_eth_rss_reta_entry64 *reta_conf,
                          uint16_t reta_size)
 {
-       uint8_t i, j, mask;
+       uint16_t i, sp_reta_size;
+       uint8_t j, mask;
        uint32_t reta, r;
        uint16_t idx, shift;
        struct ixgbe_hw *hw = IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private);
-       uint16_t sp_reta_size;
        uint32_t reta_reg;
 
        PMD_INIT_FUNC_TRACE();
@@ -3703,11 +3827,11 @@ ixgbe_dev_rss_reta_query(struct rte_eth_dev *dev,
                         struct rte_eth_rss_reta_entry64 *reta_conf,
                         uint16_t reta_size)
 {
-       uint8_t i, j, mask;
+       uint16_t i, sp_reta_size;
+       uint8_t j, mask;
        uint32_t reta;
        uint16_t idx, shift;
        struct ixgbe_hw *hw = IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private);
-       uint16_t sp_reta_size;
        uint32_t reta_reg;
 
        PMD_INIT_FUNC_TRACE();
@@ -3962,9 +4086,6 @@ ixgbevf_dev_stop(struct rte_eth_dev *dev)
 
        ixgbe_dev_clear_queues(dev);
 
-       /* disable intr eventfd mapping */
-       rte_intr_disable(intr_handle);
-
        /* Clean datapath event and queue/vec mapping */
        rte_intr_efd_disable(intr_handle);
        if (intr_handle->intr_vec != NULL) {
@@ -3986,8 +4107,12 @@ ixgbevf_dev_close(struct rte_eth_dev *dev)
 
        ixgbe_dev_free_queues(dev);
 
-       /* reprogram the RAR[0] in case user changed it. */
-       ixgbe_set_rar(hw, 0, hw->mac.addr, 0, IXGBE_RAH_AV);
+       /**
+        * Remove the VF MAC address ro ensure
+        * that the VF traffic goes to the PF
+        * after stop, close and detach of the VF
+        **/
+       ixgbevf_remove_mac_addr(dev, 0);
 }
 
 static void ixgbevf_set_vfta_all(struct rte_eth_dev *dev, bool on)
@@ -4322,10 +4447,11 @@ ixgbe_set_pool_vlan_filter(struct rte_eth_dev *dev, uint16_t vlan,
        if (ixgbe_vmdq_mode_check(hw) < 0)
                return -ENOTSUP;
        for (pool_idx = 0; pool_idx < ETH_64_POOLS; pool_idx++) {
-               if (pool_mask & ((uint64_t)(1ULL << pool_idx)))
+               if (pool_mask & ((uint64_t)(1ULL << pool_idx))) {
                        ret = hw->mac.ops.set_vfta(hw,vlan,pool_idx,vlan_on);
                        if (ret < 0)
                                return ret;
+               }
        }
 
        return ret;
@@ -4945,7 +5071,8 @@ ixgbevf_set_default_mac_addr(struct rte_eth_dev *dev, struct ether_addr *addr)
 
 #define MAC_TYPE_FILTER_SUP(type)    do {\
        if ((type) != ixgbe_mac_82599EB && (type) != ixgbe_mac_X540 &&\
-               (type) != ixgbe_mac_X550)\
+               (type) != ixgbe_mac_X550 && (type) != ixgbe_mac_X550EM_x &&\
+               (type) != ixgbe_mac_X550EM_a)\
                return -ENOTSUP;\
 } while (0)
 
@@ -5706,6 +5833,8 @@ ixgbe_read_systime_cyclecounter(struct rte_eth_dev *dev)
 
        switch (hw->mac.type) {
        case ixgbe_mac_X550:
+       case ixgbe_mac_X550EM_x:
+       case ixgbe_mac_X550EM_a:
                /* SYSTIMEL stores ns and SYSTIMEH stores seconds. */
                systime_cycles = (uint64_t)IXGBE_READ_REG(hw, IXGBE_SYSTIML);
                systime_cycles += (uint64_t)IXGBE_READ_REG(hw, IXGBE_SYSTIMH)
@@ -5728,6 +5857,8 @@ ixgbe_read_rx_tstamp_cyclecounter(struct rte_eth_dev *dev)
 
        switch (hw->mac.type) {
        case ixgbe_mac_X550:
+       case ixgbe_mac_X550EM_x:
+       case ixgbe_mac_X550EM_a:
                /* RXSTMPL stores ns and RXSTMPH stores seconds. */
                rx_tstamp_cycles = (uint64_t)IXGBE_READ_REG(hw, IXGBE_RXSTMPL);
                rx_tstamp_cycles += (uint64_t)IXGBE_READ_REG(hw, IXGBE_RXSTMPH)
@@ -5751,6 +5882,8 @@ ixgbe_read_tx_tstamp_cyclecounter(struct rte_eth_dev *dev)
 
        switch (hw->mac.type) {
        case ixgbe_mac_X550:
+       case ixgbe_mac_X550EM_x:
+       case ixgbe_mac_X550EM_a:
                /* TXSTMPL stores ns and TXSTMPH stores seconds. */
                tx_tstamp_cycles = (uint64_t)IXGBE_READ_REG(hw, IXGBE_TXSTMPL);
                tx_tstamp_cycles += (uint64_t)IXGBE_READ_REG(hw, IXGBE_TXSTMPH)
@@ -5799,6 +5932,8 @@ ixgbe_start_timecounters(struct rte_eth_dev *dev)
 
        switch (hw->mac.type) {
        case ixgbe_mac_X550:
+       case ixgbe_mac_X550EM_x:
+       case ixgbe_mac_X550EM_a:
                /* Independent of link speed. */
                incval = 1;
                /* Cycles read will be interpreted as ns. */
@@ -6122,9 +6257,11 @@ ixgbe_reta_size_get(enum ixgbe_mac_type mac_type) {
        switch (mac_type) {
        case ixgbe_mac_X550:
        case ixgbe_mac_X550EM_x:
+       case ixgbe_mac_X550EM_a:
                return ETH_RSS_RETA_SIZE_512;
        case ixgbe_mac_X550_vf:
        case ixgbe_mac_X550EM_x_vf:
+       case ixgbe_mac_X550EM_a_vf:
                return ETH_RSS_RETA_SIZE_64;
        default:
                return ETH_RSS_RETA_SIZE_128;
@@ -6136,12 +6273,14 @@ ixgbe_reta_reg_get(enum ixgbe_mac_type mac_type, uint16_t reta_idx) {
        switch (mac_type) {
        case ixgbe_mac_X550:
        case ixgbe_mac_X550EM_x:
+       case ixgbe_mac_X550EM_a:
                if (reta_idx < ETH_RSS_RETA_SIZE_128)
                        return IXGBE_RETA(reta_idx >> 2);
                else
                        return IXGBE_ERETA((reta_idx - ETH_RSS_RETA_SIZE_128) >> 2);
        case ixgbe_mac_X550_vf:
        case ixgbe_mac_X550EM_x_vf:
+       case ixgbe_mac_X550EM_a_vf:
                return IXGBE_VFRETA(reta_idx >> 2);
        default:
                return IXGBE_RETA(reta_idx >> 2);
@@ -6153,6 +6292,7 @@ ixgbe_mrqc_reg_get(enum ixgbe_mac_type mac_type) {
        switch (mac_type) {
        case ixgbe_mac_X550_vf:
        case ixgbe_mac_X550EM_x_vf:
+       case ixgbe_mac_X550EM_a_vf:
                return IXGBE_VFMRQC;
        default:
                return IXGBE_MRQC;
@@ -6164,6 +6304,7 @@ ixgbe_rssrk_reg_get(enum ixgbe_mac_type mac_type, uint8_t i) {
        switch (mac_type) {
        case ixgbe_mac_X550_vf:
        case ixgbe_mac_X550EM_x_vf:
+       case ixgbe_mac_X550EM_a_vf:
                return IXGBE_VFRSSRK(i);
        default:
                return IXGBE_RSSRK(i);
@@ -6266,7 +6407,8 @@ ixgbe_update_e_tag_eth_type(struct ixgbe_hw *hw,
        uint32_t etag_etype;
 
        if (hw->mac.type != ixgbe_mac_X550 &&
-           hw->mac.type != ixgbe_mac_X550EM_x) {
+           hw->mac.type != ixgbe_mac_X550EM_x &&
+           hw->mac.type != ixgbe_mac_X550EM_a) {
                return -ENOTSUP;
        }
 
@@ -6310,7 +6452,8 @@ ixgbe_e_tag_enable(struct ixgbe_hw *hw)
        uint32_t etag_etype;
 
        if (hw->mac.type != ixgbe_mac_X550 &&
-           hw->mac.type != ixgbe_mac_X550EM_x) {
+           hw->mac.type != ixgbe_mac_X550EM_x &&
+           hw->mac.type != ixgbe_mac_X550EM_a) {
                return -ENOTSUP;
        }
 
@@ -6350,7 +6493,8 @@ ixgbe_e_tag_disable(struct ixgbe_hw *hw)
        uint32_t etag_etype;
 
        if (hw->mac.type != ixgbe_mac_X550 &&
-           hw->mac.type != ixgbe_mac_X550EM_x) {
+           hw->mac.type != ixgbe_mac_X550EM_x &&
+           hw->mac.type != ixgbe_mac_X550EM_a) {
                return -ENOTSUP;
        }
 
@@ -6393,7 +6537,8 @@ ixgbe_e_tag_filter_del(struct rte_eth_dev *dev,
        uint32_t rar_low, rar_high;
 
        if (hw->mac.type != ixgbe_mac_X550 &&
-           hw->mac.type != ixgbe_mac_X550EM_x) {
+           hw->mac.type != ixgbe_mac_X550EM_x &&
+           hw->mac.type != ixgbe_mac_X550EM_a) {
                return -ENOTSUP;
        }
 
@@ -6428,7 +6573,8 @@ ixgbe_e_tag_filter_add(struct rte_eth_dev *dev,
        uint32_t rar_low, rar_high;
 
        if (hw->mac.type != ixgbe_mac_X550 &&
-           hw->mac.type != ixgbe_mac_X550EM_x) {
+           hw->mac.type != ixgbe_mac_X550EM_x &&
+           hw->mac.type != ixgbe_mac_X550EM_a) {
                return -ENOTSUP;
        }
 
@@ -6547,7 +6693,8 @@ ixgbe_e_tag_forwarding_en_dis(struct rte_eth_dev *dev, bool en)
        struct ixgbe_hw *hw = IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private);
 
        if (hw->mac.type != ixgbe_mac_X550 &&
-           hw->mac.type != ixgbe_mac_X550EM_x) {
+           hw->mac.type != ixgbe_mac_X550EM_x &&
+           hw->mac.type != ixgbe_mac_X550EM_a) {
                return -ENOTSUP;
        }
 
@@ -6620,7 +6767,8 @@ ixgbe_e_tag_insertion_en_dis(struct rte_eth_dev *dev,
        }
 
        if (hw->mac.type != ixgbe_mac_X550 &&
-           hw->mac.type != ixgbe_mac_X550EM_x) {
+           hw->mac.type != ixgbe_mac_X550EM_x &&
+           hw->mac.type != ixgbe_mac_X550EM_a) {
                return -ENOTSUP;
        }
 
@@ -6690,7 +6838,8 @@ ixgbe_e_tag_stripping_en_dis(struct rte_eth_dev *dev,
        struct ixgbe_hw *hw = IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private);
 
        if (hw->mac.type != ixgbe_mac_X550 &&
-           hw->mac.type != ixgbe_mac_X550EM_x) {
+           hw->mac.type != ixgbe_mac_X550EM_x &&
+           hw->mac.type != ixgbe_mac_X550EM_a) {
                return -ENOTSUP;
        }
 
@@ -6863,7 +7012,8 @@ ixgbe_dev_udp_tunnel_port_add(struct rte_eth_dev *dev,
        struct ixgbe_hw *hw = IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private);
 
        if (hw->mac.type != ixgbe_mac_X550 &&
-           hw->mac.type != ixgbe_mac_X550EM_x) {
+           hw->mac.type != ixgbe_mac_X550EM_x &&
+           hw->mac.type != ixgbe_mac_X550EM_a) {
                return -ENOTSUP;
        }
 
@@ -6899,7 +7049,8 @@ ixgbe_dev_udp_tunnel_port_del(struct rte_eth_dev *dev,
        struct ixgbe_hw *hw = IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private);
 
        if (hw->mac.type != ixgbe_mac_X550 &&
-           hw->mac.type != ixgbe_mac_X550EM_x) {
+           hw->mac.type != ixgbe_mac_X550EM_x &&
+           hw->mac.type != ixgbe_mac_X550EM_a) {
                return -ENOTSUP;
        }
 
@@ -6924,6 +7075,61 @@ ixgbe_dev_udp_tunnel_port_del(struct rte_eth_dev *dev,
        return ret;
 }
 
+/* ixgbevf_update_xcast_mode - Update Multicast mode
+ * @hw: pointer to the HW structure
+ * @netdev: pointer to net device structure
+ * @xcast_mode: new multicast mode
+ *
+ * Updates the Multicast Mode of VF.
+ */
+static int ixgbevf_update_xcast_mode(struct ixgbe_hw *hw,
+                                    int xcast_mode)
+{
+       struct ixgbe_mbx_info *mbx = &hw->mbx;
+       u32 msgbuf[2];
+       s32 err;
+
+       switch (hw->api_version) {
+       case ixgbe_mbox_api_12:
+               break;
+       default:
+               return -EOPNOTSUPP;
+       }
+
+       msgbuf[0] = IXGBE_VF_UPDATE_XCAST_MODE;
+       msgbuf[1] = xcast_mode;
+
+       err = mbx->ops.write_posted(hw, msgbuf, 2, 0);
+       if (err)
+               return err;
+
+       err = mbx->ops.read_posted(hw, msgbuf, 2, 0);
+       if (err)
+               return err;
+
+       msgbuf[0] &= ~IXGBE_VT_MSGTYPE_CTS;
+       if (msgbuf[0] == (IXGBE_VF_UPDATE_XCAST_MODE | IXGBE_VT_MSGTYPE_NACK))
+               return -EPERM;
+
+       return 0;
+}
+
+static void
+ixgbevf_dev_allmulticast_enable(struct rte_eth_dev *dev)
+{
+       struct ixgbe_hw *hw = IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+
+       ixgbevf_update_xcast_mode(hw, IXGBEVF_XCAST_MODE_ALLMULTI);
+}
+
+static void
+ixgbevf_dev_allmulticast_disable(struct rte_eth_dev *dev)
+{
+       struct ixgbe_hw *hw = IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+
+       ixgbevf_update_xcast_mode(hw, IXGBEVF_XCAST_MODE_NONE);
+}
+
 static struct rte_driver rte_ixgbe_driver = {
        .type = PMD_PDEV,
        .init = rte_ixgbe_pmd_init,