ixgbe: fix packet type from vector Rx
[dpdk.git] / drivers / net / ixgbe / ixgbe_ethdev.c
index 9a392b9..6ce4111 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;
 
@@ -1904,11 +1920,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;
@@ -2017,6 +2040,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,6 +2107,8 @@ 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) &&
@@ -2248,9 +2292,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 +2649,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 +
@@ -2893,6 +2933,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)
@@ -3146,6 +3219,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 +3279,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 +3289,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 +3357,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 +3739,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 +3793,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 +4052,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 +4073,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)
@@ -6122,9 +6213,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 +6229,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 +6248,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 +6260,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);
@@ -6924,6 +7021,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,