New upstream version 16.11.3
[deb_dpdk.git] / drivers / net / i40e / i40e_ethdev.c
index 67778ba..65e10f3 100644 (file)
@@ -1,7 +1,7 @@
 /*-
  *   BSD LICENSE
  *
- *   Copyright(c) 2010-2016 Intel Corporation. All rights reserved.
+ *   Copyright(c) 2010-2017 Intel Corporation. All rights reserved.
  *   All rights reserved.
  *
  *   Redistribution and use in source and binary forms, with or without
@@ -460,6 +460,7 @@ static void i40e_set_default_mac_addr(struct rte_eth_dev *dev,
                                      struct ether_addr *mac_addr);
 
 static int i40e_dev_mtu_set(struct rte_eth_dev *dev, uint16_t mtu);
+static void i40e_notify_all_vfs_link_status(struct rte_eth_dev *dev);
 
 static const struct rte_pci_id pci_id_i40e_map[] = {
        { RTE_PCI_DEVICE(I40E_INTEL_VENDOR_ID, I40E_DEV_ID_SFP_XL710) },
@@ -1590,11 +1591,15 @@ i40e_parse_link_speeds(uint16_t link_speeds)
 static int
 i40e_phy_conf_link(struct i40e_hw *hw,
                   uint8_t abilities,
-                  uint8_t force_speed)
+                  uint8_t force_speed,
+                  bool is_up)
 {
        enum i40e_status_code status;
        struct i40e_aq_get_phy_abilities_resp phy_ab;
        struct i40e_aq_set_phy_config phy_conf;
+       enum i40e_aq_phy_type cnt;
+       uint32_t phy_type_mask = 0;
+
        const uint8_t mask = I40E_AQ_PHY_FLAG_PAUSE_TX |
                        I40E_AQ_PHY_FLAG_PAUSE_RX |
                        I40E_AQ_PHY_FLAG_PAUSE_RX |
@@ -1612,6 +1617,10 @@ i40e_phy_conf_link(struct i40e_hw *hw,
        if (status)
                return ret;
 
+       /* If link already up, no need to set up again */
+       if (is_up && phy_ab.phy_type != 0)
+               return I40E_SUCCESS;
+
        memset(&phy_conf, 0, sizeof(phy_conf));
 
        /* bits 0-2 use the values from get_phy_abilities_resp */
@@ -1622,12 +1631,22 @@ i40e_phy_conf_link(struct i40e_hw *hw,
        if (abilities & I40E_AQ_PHY_AN_ENABLED)
                phy_conf.link_speed = advt;
        else
-               phy_conf.link_speed = force_speed;
+               phy_conf.link_speed = is_up ? force_speed : phy_ab.link_speed;
 
        phy_conf.abilities = abilities;
 
+
+
+       /* To enable link, phy_type mask needs to include each type */
+       for (cnt = I40E_PHY_TYPE_SGMII; cnt < I40E_PHY_TYPE_MAX; cnt++)
+               phy_type_mask |= 1 << cnt;
+
        /* use get_phy_abilities_resp value for the rest */
-       phy_conf.phy_type = phy_ab.phy_type;
+       phy_conf.phy_type = is_up ? cpu_to_le32(phy_type_mask) : 0;
+       phy_conf.phy_type_ext = is_up ? (I40E_AQ_PHY_TYPE_EXT_25G_KR |
+               I40E_AQ_PHY_TYPE_EXT_25G_CR | I40E_AQ_PHY_TYPE_EXT_25G_SR |
+               I40E_AQ_PHY_TYPE_EXT_25G_LR) : 0;
+       phy_conf.fec_config = phy_ab.mod_type_ext;
        phy_conf.eee_capability = phy_ab.eee_capability;
        phy_conf.eeer = phy_ab.eeer_val;
        phy_conf.low_power_ctrl = phy_ab.d3_lpan;
@@ -1653,19 +1672,12 @@ i40e_apply_link_speed(struct rte_eth_dev *dev)
        struct rte_eth_conf *conf = &dev->data->dev_conf;
 
        speed = i40e_parse_link_speeds(conf->link_speeds);
-       if (!I40E_PHY_TYPE_SUPPORT_25G(hw->phy.phy_types))
-               abilities |= I40E_AQ_PHY_ENABLE_ATOMIC_LINK;
+       abilities |= I40E_AQ_PHY_ENABLE_ATOMIC_LINK;
        if (!(conf->link_speeds & ETH_LINK_SPEED_FIXED))
                abilities |= I40E_AQ_PHY_AN_ENABLED;
        abilities |= I40E_AQ_PHY_LINK_ENABLED;
 
-       /* Skip changing speed on 40G interfaces, FW does not support */
-       if (I40E_PHY_TYPE_SUPPORT_40G(hw->phy.phy_types)) {
-               speed =  I40E_LINK_SPEED_UNKNOWN;
-               abilities |= I40E_AQ_PHY_AN_ENABLED;
-       }
-
-       return i40e_phy_conf_link(hw, abilities, speed);
+       return i40e_phy_conf_link(hw, abilities, speed, true);
 }
 
 static int
@@ -1875,18 +1887,17 @@ i40e_dev_close(struct rte_eth_dev *dev)
        /* shutdown and destroy the HMC */
        i40e_shutdown_lan_hmc(hw);
 
-       /* release all the existing VSIs and VEBs */
-       i40e_fdir_teardown(pf);
-       i40e_vsi_release(pf->main_vsi);
-
        for (i = 0; i < pf->nb_cfg_vmdq_vsi; i++) {
                i40e_vsi_release(pf->vmdq[i].vsi);
                pf->vmdq[i].vsi = NULL;
        }
-
        rte_free(pf->vmdq);
        pf->vmdq = NULL;
 
+       /* release all the existing VSIs and VEBs */
+       i40e_fdir_teardown(pf);
+       i40e_vsi_release(pf->main_vsi);
+
        /* shutdown the adminq */
        i40e_aq_queue_shutdown(hw, true);
        i40e_shutdown_adminq(hw);
@@ -1990,9 +2001,8 @@ i40e_dev_set_link_down(struct rte_eth_dev *dev)
        uint8_t abilities = 0;
        struct i40e_hw *hw = I40E_DEV_PRIVATE_TO_HW(dev->data->dev_private);
 
-       if (!I40E_PHY_TYPE_SUPPORT_25G(hw->phy.phy_types))
-               abilities = I40E_AQ_PHY_ENABLE_ATOMIC_LINK;
-       return i40e_phy_conf_link(hw, abilities, speed);
+       abilities = I40E_AQ_PHY_ENABLE_ATOMIC_LINK;
+       return i40e_phy_conf_link(hw, abilities, speed, false);
 }
 
 int
@@ -2025,11 +2035,11 @@ i40e_dev_link_update(struct rte_eth_dev *dev,
                }
 
                link.link_status = link_status.link_info & I40E_AQ_LINK_UP;
-               if (!wait_to_complete)
+               if (!wait_to_complete || link.link_status)
                        break;
 
                rte_delay_ms(CHECK_INTERVAL);
-       } while (!link.link_status && rep_cnt--);
+       } while (--rep_cnt);
 
        if (!link.link_status)
                goto out;
@@ -2070,6 +2080,8 @@ out:
        if (link.link_status == old.link_status)
                return -1;
 
+       i40e_notify_all_vfs_link_status(dev);
+
        return 0;
 }
 
@@ -2094,6 +2106,10 @@ i40e_update_vsi_stats(struct i40e_vsi *vsi)
        i40e_stat_update_48(hw, I40E_GLV_BPRCH(idx), I40E_GLV_BPRCL(idx),
                            vsi->offset_loaded, &oes->rx_broadcast,
                            &nes->rx_broadcast);
+       /* exclude CRC bytes */
+       nes->rx_bytes -= (nes->rx_unicast + nes->rx_multicast +
+               nes->rx_broadcast) * ETHER_CRC_LEN;
+
        i40e_stat_update_32(hw, I40E_GLV_RDPC(idx), vsi->offset_loaded,
                            &oes->rx_discards, &nes->rx_discards);
        /* GLV_REPC not supported */
@@ -2113,6 +2129,9 @@ i40e_update_vsi_stats(struct i40e_vsi *vsi)
        i40e_stat_update_48(hw, I40E_GLV_BPTCH(idx), I40E_GLV_BPTCL(idx),
                            vsi->offset_loaded,  &oes->tx_broadcast,
                            &nes->tx_broadcast);
+       /* exclude CRC bytes */
+       nes->tx_bytes -= (nes->tx_unicast + nes->tx_multicast +
+               nes->tx_broadcast) * ETHER_CRC_LEN;
        /* GLV_TDPC not supported */
        i40e_stat_update_32(hw, I40E_GLV_TEPC(idx), vsi->offset_loaded,
                            &oes->tx_errors, &nes->tx_errors);
@@ -2144,6 +2163,19 @@ i40e_read_stats_registers(struct i40e_pf *pf, struct i40e_hw *hw)
        struct i40e_hw_port_stats *ns = &pf->stats; /* new stats */
        struct i40e_hw_port_stats *os = &pf->stats_offset; /* old stats */
 
+       /* Get rx/tx bytes of internal transfer packets */
+       i40e_stat_update_48(hw, I40E_GLV_GORCH(hw->port),
+                       I40E_GLV_GORCL(hw->port),
+                       pf->offset_loaded,
+                       &pf->internal_rx_bytes_offset,
+                       &pf->internal_rx_bytes);
+
+       i40e_stat_update_48(hw, I40E_GLV_GOTCH(hw->port),
+                       I40E_GLV_GOTCL(hw->port),
+                       pf->offset_loaded,
+                       &pf->internal_tx_bytes_offset,
+                       &pf->internal_tx_bytes);
+
        /* Get statistics of struct i40e_eth_stats */
        i40e_stat_update_48(hw, I40E_GLPRT_GORCH(hw->port),
                            I40E_GLPRT_GORCL(hw->port),
@@ -2165,7 +2197,7 @@ i40e_read_stats_registers(struct i40e_pf *pf, struct i40e_hw *hw)
         * so subtract ETHER_CRC_LEN from the byte counter for each rx packet.
         */
        ns->eth.rx_bytes -= (ns->eth.rx_unicast + ns->eth.rx_multicast +
-               ns->eth.rx_broadcast) * ETHER_CRC_LEN;
+               ns->eth.rx_broadcast) * ETHER_CRC_LEN + pf->internal_rx_bytes;
 
        i40e_stat_update_32(hw, I40E_GLPRT_RDPC(hw->port),
                            pf->offset_loaded, &os->eth.rx_discards,
@@ -2193,7 +2225,7 @@ i40e_read_stats_registers(struct i40e_pf *pf, struct i40e_hw *hw)
                            pf->offset_loaded, &os->eth.tx_broadcast,
                            &ns->eth.tx_broadcast);
        ns->eth.tx_bytes -= (ns->eth.tx_unicast + ns->eth.tx_multicast +
-               ns->eth.tx_broadcast) * ETHER_CRC_LEN;
+               ns->eth.tx_broadcast) * ETHER_CRC_LEN + pf->internal_tx_bytes;
        /* GLPRT_TEPC not supported */
 
        /* additional port specific stats */
@@ -2532,6 +2564,7 @@ i40e_dev_xstats_get(struct rte_eth_dev *dev, struct rte_eth_xstat *xstats,
        for (i = 0; i < I40E_NB_ETH_XSTATS; i++) {
                xstats[count].value = *(uint64_t *)(((char *)&hw_stats->eth) +
                        rte_i40e_stats_strings[i].offset);
+               xstats[count].id = count;
                count++;
        }
 
@@ -2539,6 +2572,7 @@ i40e_dev_xstats_get(struct rte_eth_dev *dev, struct rte_eth_xstat *xstats,
        for (i = 0; i < I40E_NB_HW_PORT_XSTATS; i++) {
                xstats[count].value = *(uint64_t *)(((char *)hw_stats) +
                        rte_i40e_hw_port_strings[i].offset);
+               xstats[count].id = count;
                count++;
        }
 
@@ -2548,6 +2582,7 @@ i40e_dev_xstats_get(struct rte_eth_dev *dev, struct rte_eth_xstat *xstats,
                                *(uint64_t *)(((char *)hw_stats) +
                                rte_i40e_rxq_prio_strings[i].offset +
                                (sizeof(uint64_t) * prio));
+                       xstats[count].id = count;
                        count++;
                }
        }
@@ -2558,6 +2593,7 @@ i40e_dev_xstats_get(struct rte_eth_dev *dev, struct rte_eth_xstat *xstats,
                                *(uint64_t *)(((char *)hw_stats) +
                                rte_i40e_txq_prio_strings[i].offset +
                                (sizeof(uint64_t) * prio));
+                       xstats[count].id = count;
                        count++;
                }
        }
@@ -3986,6 +4022,8 @@ i40e_vsi_config_tc_queue_mapping(struct i40e_vsi *vsi,
        for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++)
                if (enabled_tcmap & (1 << i))
                        total_tc++;
+       if (total_tc == 0)
+               total_tc = 1;
        vsi->enabled_tc = enabled_tcmap;
 
        /* Number of queues per enabled TC */
@@ -4102,6 +4140,7 @@ i40e_veb_setup(struct i40e_pf *pf, struct i40e_vsi *vsi)
                            hw->aq.asq_last_status);
                goto fail;
        }
+       veb->enabled_tc = I40E_DEFAULT_TCMAP;
 
        /* get statistics index */
        ret = i40e_aq_get_veb_parameters(hw, veb->seid, NULL, NULL,
@@ -4136,6 +4175,9 @@ i40e_vsi_release(struct i40e_vsi *vsi)
        if (!vsi)
                return I40E_SUCCESS;
 
+       if (!vsi->adapter)
+               return -EFAULT;
+
        user_param = vsi->user_param;
 
        pf = I40E_VSI_TO_PF(vsi);
@@ -4910,6 +4952,10 @@ i40e_pf_setup(struct i40e_pf *pf)
        pf->offset_loaded = FALSE;
        memset(&pf->stats, 0, sizeof(struct i40e_hw_port_stats));
        memset(&pf->stats_offset, 0, sizeof(struct i40e_hw_port_stats));
+       pf->internal_rx_bytes = 0;
+       pf->internal_tx_bytes = 0;
+       pf->internal_rx_bytes_offset = 0;
+       pf->internal_tx_bytes_offset = 0;
 
        ret = i40e_pf_get_switch_config(pf);
        if (ret != I40E_SUCCESS) {
@@ -5498,11 +5544,9 @@ i40e_dev_handle_aq_msg(struct rte_eth_dev *dev)
                        break;
                case i40e_aqc_opc_get_link_status:
                        ret = i40e_dev_link_update(dev, 0);
-                       if (!ret) {
-                               i40e_notify_all_vfs_link_status(dev);
+                       if (!ret)
                                _rte_eth_dev_callback_process(dev,
                                        RTE_ETH_EVENT_INTR_LSC, NULL);
-                       }
                        break;
                default:
                        PMD_DRV_LOG(ERR, "Request %u is not supported yet",
@@ -5844,7 +5888,7 @@ i40e_find_all_mac_for_vlan(struct i40e_vsi *vsi,
 static int
 i40e_vsi_remove_all_macvlan_filter(struct i40e_vsi *vsi)
 {
-       int i, num;
+       int i, j, num;
        struct i40e_mac_filter *f;
        struct i40e_macvlan_filter *mv_f;
        int ret = I40E_SUCCESS;
@@ -5869,6 +5913,7 @@ i40e_vsi_remove_all_macvlan_filter(struct i40e_vsi *vsi)
                TAILQ_FOREACH(f, &vsi->mac_list, next) {
                        (void)rte_memcpy(&mv_f[i].macaddr,
                                &f->mac_info.mac_addr, ETH_ADDR_LEN);
+                       mv_f[i].filter_type = f->mac_info.filter_type;
                        mv_f[i].vlan_id = 0;
                        i++;
                }
@@ -5878,6 +5923,8 @@ i40e_vsi_remove_all_macvlan_filter(struct i40e_vsi *vsi)
                                        vsi->vlan_num, &f->mac_info.mac_addr);
                        if (ret != I40E_SUCCESS)
                                goto DONE;
+                       for (j = i; j < i + vsi->vlan_num; j++)
+                               mv_f[j].filter_type = f->mac_info.filter_type;
                        i += vsi->vlan_num;
                }
        }
@@ -7042,7 +7089,44 @@ i40e_set_hash_filter_global_config(struct i40e_hw *hw,
                pctype = i40e_flowtype_to_pctype(i);
                reg = (g_cfg->sym_hash_enable_mask[0] & (1UL << i)) ?
                                I40E_GLQF_HSYM_SYMH_ENA_MASK : 0;
-               i40e_write_rx_ctl(hw, I40E_GLQF_HSYM(pctype), reg);
+               if (hw->mac.type == I40E_MAC_X722) {
+                       if (pctype == I40E_FILTER_PCTYPE_NONF_IPV4_UDP) {
+                               i40e_write_rx_ctl(hw, I40E_GLQF_HSYM(
+                                 I40E_FILTER_PCTYPE_NONF_IPV4_UDP), reg);
+                               i40e_write_rx_ctl(hw, I40E_GLQF_HSYM(
+                                 I40E_FILTER_PCTYPE_NONF_UNICAST_IPV4_UDP),
+                                 reg);
+                               i40e_write_rx_ctl(hw, I40E_GLQF_HSYM(
+                                 I40E_FILTER_PCTYPE_NONF_MULTICAST_IPV4_UDP),
+                                 reg);
+                       } else if (pctype == I40E_FILTER_PCTYPE_NONF_IPV4_TCP) {
+                               i40e_write_rx_ctl(hw, I40E_GLQF_HSYM(
+                                 I40E_FILTER_PCTYPE_NONF_IPV4_TCP), reg);
+                               i40e_write_rx_ctl(hw, I40E_GLQF_HSYM(
+                                 I40E_FILTER_PCTYPE_NONF_IPV4_TCP_SYN_NO_ACK),
+                                 reg);
+                       } else if (pctype == I40E_FILTER_PCTYPE_NONF_IPV6_UDP) {
+                               i40e_write_rx_ctl(hw, I40E_GLQF_HSYM(
+                                 I40E_FILTER_PCTYPE_NONF_IPV6_UDP), reg);
+                               i40e_write_rx_ctl(hw, I40E_GLQF_HSYM(
+                                 I40E_FILTER_PCTYPE_NONF_UNICAST_IPV6_UDP),
+                                 reg);
+                               i40e_write_rx_ctl(hw, I40E_GLQF_HSYM(
+                                 I40E_FILTER_PCTYPE_NONF_MULTICAST_IPV6_UDP),
+                                 reg);
+                       } else if (pctype == I40E_FILTER_PCTYPE_NONF_IPV6_TCP) {
+                               i40e_write_rx_ctl(hw, I40E_GLQF_HSYM(
+                                 I40E_FILTER_PCTYPE_NONF_IPV6_TCP), reg);
+                               i40e_write_rx_ctl(hw, I40E_GLQF_HSYM(
+                                 I40E_FILTER_PCTYPE_NONF_IPV6_TCP_SYN_NO_ACK),
+                                 reg);
+                       } else {
+                               i40e_write_rx_ctl(hw, I40E_GLQF_HSYM(pctype),
+                                 reg);
+                       }
+               } else {
+                       i40e_write_rx_ctl(hw, I40E_GLQF_HSYM(pctype), reg);
+               }
        }
 
        reg = i40e_read_rx_ctl(hw, I40E_GLQF_CTL);
@@ -8269,12 +8353,17 @@ i40e_pctype_to_flowtype(enum i40e_filter_pctype pctype)
  */
 
 /* For both X710 and XL710 */
-#define I40E_GL_SWR_PRI_JOIN_MAP_0_VALUE 0x10000200
-#define I40E_GL_SWR_PRI_JOIN_MAP_0       0x26CE00
+#define I40E_GL_SWR_PRI_JOIN_MAP_0_VALUE_1     0x10000200
+#define I40E_GL_SWR_PRI_JOIN_MAP_0_VALUE_2     0x20000200
+#define I40E_GL_SWR_PRI_JOIN_MAP_0             0x26CE00
 
 #define I40E_GL_SWR_PRI_JOIN_MAP_2_VALUE 0x011f0200
 #define I40E_GL_SWR_PRI_JOIN_MAP_2       0x26CE08
 
+/* For X722 */
+#define I40E_X722_GL_SWR_PRI_JOIN_MAP_0_VALUE 0x20000200
+#define I40E_X722_GL_SWR_PRI_JOIN_MAP_2_VALUE 0x013F0200
+
 /* For X710 */
 #define I40E_GL_SWR_PM_UP_THR_EF_VALUE   0x03030303
 /* For XL710 */
@@ -8297,7 +8386,6 @@ i40e_dev_sync_phy_type(struct i40e_hw *hw)
        return 0;
 }
 
-
 static void
 i40e_configure_registers(struct i40e_hw *hw)
 {
@@ -8305,8 +8393,8 @@ i40e_configure_registers(struct i40e_hw *hw)
                uint32_t addr;
                uint64_t val;
        } reg_table[] = {
-               {I40E_GL_SWR_PRI_JOIN_MAP_0, I40E_GL_SWR_PRI_JOIN_MAP_0_VALUE},
-               {I40E_GL_SWR_PRI_JOIN_MAP_2, I40E_GL_SWR_PRI_JOIN_MAP_2_VALUE},
+               {I40E_GL_SWR_PRI_JOIN_MAP_0, 0},
+               {I40E_GL_SWR_PRI_JOIN_MAP_2, 0},
                {I40E_GL_SWR_PM_UP_THR, 0}, /* Compute value dynamically */
        };
        uint64_t reg;
@@ -8314,6 +8402,28 @@ i40e_configure_registers(struct i40e_hw *hw)
        int ret;
 
        for (i = 0; i < RTE_DIM(reg_table); i++) {
+               if (reg_table[i].addr == I40E_GL_SWR_PRI_JOIN_MAP_0) {
+                       if (hw->mac.type == I40E_MAC_X722) /* For X722 */
+                               reg_table[i].val =
+                                       I40E_X722_GL_SWR_PRI_JOIN_MAP_0_VALUE;
+                       else /* For X710/XL710/XXV710 */
+                               if (hw->aq.fw_maj_ver < 6)
+                                       reg_table[i].val =
+                                            I40E_GL_SWR_PRI_JOIN_MAP_0_VALUE_1;
+                               else
+                                       reg_table[i].val =
+                                            I40E_GL_SWR_PRI_JOIN_MAP_0_VALUE_2;
+               }
+
+               if (reg_table[i].addr == I40E_GL_SWR_PRI_JOIN_MAP_2) {
+                       if (hw->mac.type == I40E_MAC_X722) /* For X722 */
+                               reg_table[i].val =
+                                       I40E_X722_GL_SWR_PRI_JOIN_MAP_2_VALUE;
+                       else /* For X710/XL710/XXV710 */
+                               reg_table[i].val =
+                                       I40E_GL_SWR_PRI_JOIN_MAP_2_VALUE;
+               }
+
                if (reg_table[i].addr == I40E_GL_SWR_PM_UP_THR) {
                        if (I40E_PHY_TYPE_SUPPORT_40G(hw->phy.phy_types) || /* For XL710 */
                            I40E_PHY_TYPE_SUPPORT_25G(hw->phy.phy_types)) /* For XXV710 */