X-Git-Url: http://git.droids-corp.org/?a=blobdiff_plain;f=lib%2Flibrte_pmd_ixgbe%2Fixgbe_ethdev.c;h=eb31bd91b490303fdfc4cde1662938dc3ee1715b;hb=3031749c2df04a63cdcef186dcce3781e61436e8;hp=613e49df8818037e476312003a668d99b56e3b57;hpb=563455467f3d3523a4f51db05ccaae5bd1809c71;p=dpdk.git diff --git a/lib/librte_pmd_ixgbe/ixgbe_ethdev.c b/lib/librte_pmd_ixgbe/ixgbe_ethdev.c index 613e49df88..eb31bd91b4 100644 --- a/lib/librte_pmd_ixgbe/ixgbe_ethdev.c +++ b/lib/librte_pmd_ixgbe/ixgbe_ethdev.c @@ -1,35 +1,34 @@ /*- * BSD LICENSE - * - * Copyright(c) 2010-2012 Intel Corporation. All rights reserved. + * + * Copyright(c) 2010-2014 Intel Corporation. All rights reserved. * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions * are met: - * - * * Redistributions of source code must retain the above copyright + * + * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the * distribution. - * * Neither the name of Intel Corporation nor the names of its - * contributors may be used to endorse or promote products derived + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * */ #include @@ -59,12 +58,15 @@ #include #include #include +#include +#include #include "ixgbe_logs.h" #include "ixgbe/ixgbe_api.h" #include "ixgbe/ixgbe_vf.h" #include "ixgbe/ixgbe_common.h" #include "ixgbe_ethdev.h" +#include "ixgbe_bypass.h" /* * High threshold controlling when to start sending XOFF frames. Must be at @@ -84,13 +86,16 @@ #define IXGBE_LINK_DOWN_CHECK_TIMEOUT 4000 /* ms */ #define IXGBE_LINK_UP_CHECK_TIMEOUT 1000 /* ms */ +#define IXGBE_VMDQ_NUM_UC_MAC 4096 /* Maximum nb. of UC MAC addr. */ + + +#define IXGBEVF_PMD_NAME "rte_ixgbevf_pmd" /* PMD name */ #define IXGBE_QUEUE_STAT_COUNTERS (sizeof(hw_stats->qprc) / sizeof(hw_stats->qprc[0])) static int eth_ixgbe_dev_init(struct eth_driver *eth_drv, struct rte_eth_dev *eth_dev); -static int ixgbe_dev_configure(struct rte_eth_dev *dev, uint16_t nb_rx_q, - uint16_t nb_tx_q); +static int ixgbe_dev_configure(struct rte_eth_dev *dev); static int ixgbe_dev_start(struct rte_eth_dev *dev); static void ixgbe_dev_stop(struct rte_eth_dev *dev); static void ixgbe_dev_close(struct rte_eth_dev *dev); @@ -109,38 +114,83 @@ 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 void ixgbe_vlan_filter_set(struct rte_eth_dev *dev, - uint16_t vlan_id, - int on); +static int ixgbe_vlan_filter_set(struct rte_eth_dev *dev, + uint16_t vlan_id, int on); +static void ixgbe_vlan_tpid_set(struct rte_eth_dev *dev, uint16_t tpid_id); +static void ixgbe_vlan_hw_strip_bitmap_set(struct rte_eth_dev *dev, + uint16_t queue, bool on); +static void ixgbe_vlan_strip_queue_set(struct rte_eth_dev *dev, uint16_t queue, + int on); +static void ixgbe_vlan_offload_set(struct rte_eth_dev *dev, int mask); +static void ixgbe_vlan_hw_strip_enable(struct rte_eth_dev *dev, uint16_t queue); +static void ixgbe_vlan_hw_strip_disable(struct rte_eth_dev *dev, uint16_t queue); +static void ixgbe_vlan_hw_extend_enable(struct rte_eth_dev *dev); +static void ixgbe_vlan_hw_extend_disable(struct rte_eth_dev *dev); + static int ixgbe_dev_led_on(struct rte_eth_dev *dev); static int ixgbe_dev_led_off(struct rte_eth_dev *dev); static int ixgbe_flow_ctrl_set(struct rte_eth_dev *dev, - struct rte_eth_fc_conf *fc_conf); + struct rte_eth_fc_conf *fc_conf); +static int ixgbe_priority_flow_ctrl_set(struct rte_eth_dev *dev, + struct rte_eth_pfc_conf *pfc_conf); +static int ixgbe_dev_rss_reta_update(struct rte_eth_dev *dev, + struct rte_eth_rss_reta *reta_conf); +static int ixgbe_dev_rss_reta_query(struct rte_eth_dev *dev, + struct rte_eth_rss_reta *reta_conf); static void ixgbe_dev_link_status_print(struct rte_eth_dev *dev); -static int ixgbe_dev_interrupt_setup(struct rte_eth_dev *dev); +static int ixgbe_dev_lsc_interrupt_setup(struct rte_eth_dev *dev); static int ixgbe_dev_interrupt_get_status(struct rte_eth_dev *dev); static int ixgbe_dev_interrupt_action(struct rte_eth_dev *dev); static void ixgbe_dev_interrupt_handler(struct rte_intr_handle *handle, - void *param); + void *param); static void ixgbe_dev_interrupt_delayed_handler(void *param); static void ixgbe_add_rar(struct rte_eth_dev *dev, struct ether_addr *mac_addr, - uint32_t index, uint32_t pool); + uint32_t index, uint32_t pool); static void ixgbe_remove_rar(struct rte_eth_dev *dev, uint32_t index); +static void ixgbe_dcb_init(struct ixgbe_hw *hw,struct ixgbe_dcb_config *dcb_config); /* For Virtual Function support */ static int eth_ixgbevf_dev_init(struct eth_driver *eth_drv, struct rte_eth_dev *eth_dev); -static int ixgbevf_dev_configure(struct rte_eth_dev *dev, uint16_t nb_rx_q, - uint16_t nb_tx_q); +static int ixgbevf_dev_configure(struct rte_eth_dev *dev); static int ixgbevf_dev_start(struct rte_eth_dev *dev); static void ixgbevf_dev_stop(struct rte_eth_dev *dev); +static void ixgbevf_dev_close(struct rte_eth_dev *dev); static void ixgbevf_intr_disable(struct ixgbe_hw *hw); -static void ixgbevf_dev_stats_get(struct rte_eth_dev *dev, struct rte_eth_stats *stats); +static void ixgbevf_dev_stats_get(struct rte_eth_dev *dev, + struct rte_eth_stats *stats); static void ixgbevf_dev_stats_reset(struct rte_eth_dev *dev); +static int ixgbevf_vlan_filter_set(struct rte_eth_dev *dev, + uint16_t vlan_id, int on); +static void ixgbevf_vlan_strip_queue_set(struct rte_eth_dev *dev, + uint16_t queue, int on); +static void ixgbevf_vlan_offload_set(struct rte_eth_dev *dev, int mask); +static void ixgbevf_set_vfta_all(struct rte_eth_dev *dev, bool on); + +/* For Eth VMDQ APIs support */ +static int ixgbe_uc_hash_table_set(struct rte_eth_dev *dev, struct + ether_addr* mac_addr,uint8_t on); +static int ixgbe_uc_all_hash_table_set(struct rte_eth_dev *dev,uint8_t on); +static int ixgbe_set_pool_rx_mode(struct rte_eth_dev *dev, uint16_t pool, + uint16_t rx_mask, uint8_t on); +static int ixgbe_set_pool_rx(struct rte_eth_dev *dev,uint16_t pool,uint8_t on); +static int ixgbe_set_pool_tx(struct rte_eth_dev *dev,uint16_t pool,uint8_t on); +static int ixgbe_set_pool_vlan_filter(struct rte_eth_dev *dev, uint16_t vlan, + uint64_t pool_mask,uint8_t vlan_on); +static int ixgbe_mirror_rule_set(struct rte_eth_dev *dev, + struct rte_eth_vmdq_mirror_conf *mirror_conf, + uint8_t rule_id, uint8_t on); +static int ixgbe_mirror_rule_reset(struct rte_eth_dev *dev, + uint8_t rule_id); + +static void ixgbevf_add_mac_addr(struct rte_eth_dev *dev, + struct ether_addr *mac_addr, + uint32_t index, uint32_t pool); +static void ixgbevf_remove_mac_addr(struct rte_eth_dev *dev, uint32_t index); /* - * * Define VF Stats MACRO for Non "cleared on read" register - * */ + * Define VF Stats MACRO for Non "cleared on read" register + */ #define UPDATE_VF_STAT(reg, last, cur) \ { \ u32 latest = IXGBE_READ_REG(hw, reg); \ @@ -157,13 +207,30 @@ static void ixgbevf_dev_stats_reset(struct rte_eth_dev *dev); last = latest; \ } +#define IXGBE_SET_HWSTRIP(h, q) do{\ + uint32_t idx = (q) / (sizeof ((h)->bitmap[0]) * NBBY); \ + uint32_t bit = (q) % (sizeof ((h)->bitmap[0]) * NBBY); \ + (h)->bitmap[idx] |= 1 << bit;\ + }while(0) + +#define IXGBE_CLEAR_HWSTRIP(h, q) do{\ + uint32_t idx = (q) / (sizeof ((h)->bitmap[0]) * NBBY); \ + uint32_t bit = (q) % (sizeof ((h)->bitmap[0]) * NBBY); \ + (h)->bitmap[idx] &= ~(1 << bit);\ + }while(0) + +#define IXGBE_GET_HWSTRIP(h, q, r) do{\ + uint32_t idx = (q) / (sizeof ((h)->bitmap[0]) * NBBY); \ + uint32_t bit = (q) % (sizeof ((h)->bitmap[0]) * NBBY); \ + (r) = (h)->bitmap[idx] >> bit & 1;\ + }while(0) + /* * The set of PCI devices this driver supports */ static struct rte_pci_id pci_id_ixgbe_map[] = { -#undef RTE_LIBRTE_IGB_PMD -#define RTE_PCI_DEV_ID_DECL(vend, dev) {RTE_PCI_DEVICE(vend, dev)}, +#define RTE_PCI_DEV_ID_DECL_IXGBE(vend, dev) {RTE_PCI_DEVICE(vend, dev)}, #include "rte_pci_dev_ids.h" { .vendor_id = 0, /* sentinel */ }, @@ -174,13 +241,11 @@ static struct rte_pci_id pci_id_ixgbe_map[] = { * The set of PCI devices this driver supports (for 82599 VF) */ static struct rte_pci_id pci_id_ixgbevf_map[] = { -{ - .vendor_id = PCI_VENDOR_ID_INTEL, - .device_id = IXGBE_DEV_ID_82599_VF, - .subsystem_vendor_id = PCI_ANY_ID, - .subsystem_device_id = PCI_ANY_ID, -}, + +#define RTE_PCI_DEV_ID_DECL_IXGBEVF(vend, dev) {RTE_PCI_DEVICE(vend, dev)}, +#include "rte_pci_dev_ids.h" { .vendor_id = 0, /* sentinel */ }, + }; static struct eth_dev_ops ixgbe_eth_dev_ops = { @@ -198,13 +263,33 @@ static struct eth_dev_ops ixgbe_eth_dev_ops = { .queue_stats_mapping_set = ixgbe_dev_queue_stats_mapping_set, .dev_infos_get = ixgbe_dev_info_get, .vlan_filter_set = ixgbe_vlan_filter_set, + .vlan_tpid_set = ixgbe_vlan_tpid_set, + .vlan_offload_set = ixgbe_vlan_offload_set, + .vlan_strip_queue_set = ixgbe_vlan_strip_queue_set, + .rx_queue_start = ixgbe_dev_rx_queue_start, + .rx_queue_stop = ixgbe_dev_rx_queue_stop, + .tx_queue_start = ixgbe_dev_tx_queue_start, + .tx_queue_stop = ixgbe_dev_tx_queue_stop, .rx_queue_setup = ixgbe_dev_rx_queue_setup, + .rx_queue_release = ixgbe_dev_rx_queue_release, + .rx_queue_count = ixgbe_dev_rx_queue_count, + .rx_descriptor_done = ixgbe_dev_rx_descriptor_done, .tx_queue_setup = ixgbe_dev_tx_queue_setup, + .tx_queue_release = ixgbe_dev_tx_queue_release, .dev_led_on = ixgbe_dev_led_on, .dev_led_off = ixgbe_dev_led_off, .flow_ctrl_set = ixgbe_flow_ctrl_set, + .priority_flow_ctrl_set = ixgbe_priority_flow_ctrl_set, .mac_addr_add = ixgbe_add_rar, .mac_addr_remove = ixgbe_remove_rar, + .uc_hash_table_set = ixgbe_uc_hash_table_set, + .uc_all_hash_table_set = ixgbe_uc_all_hash_table_set, + .mirror_rule_set = ixgbe_mirror_rule_set, + .mirror_rule_reset = ixgbe_mirror_rule_reset, + .set_vf_rx_mode = ixgbe_set_pool_rx_mode, + .set_vf_rx = ixgbe_set_pool_rx, + .set_vf_tx = ixgbe_set_pool_tx, + .set_vf_vlan_filter = ixgbe_set_pool_vlan_filter, .fdir_add_signature_filter = ixgbe_fdir_add_signature_filter, .fdir_update_signature_filter = ixgbe_fdir_update_signature_filter, .fdir_remove_signature_filter = ixgbe_fdir_remove_signature_filter, @@ -213,6 +298,21 @@ static struct eth_dev_ops ixgbe_eth_dev_ops = { .fdir_update_perfect_filter = ixgbe_fdir_update_perfect_filter, .fdir_remove_perfect_filter = ixgbe_fdir_remove_perfect_filter, .fdir_set_masks = ixgbe_fdir_set_masks, + .reta_update = ixgbe_dev_rss_reta_update, + .reta_query = ixgbe_dev_rss_reta_query, +#ifdef RTE_NIC_BYPASS + .bypass_init = ixgbe_bypass_init, + .bypass_state_set = ixgbe_bypass_state_store, + .bypass_state_show = ixgbe_bypass_state_show, + .bypass_event_set = ixgbe_bypass_event_store, + .bypass_event_show = ixgbe_bypass_event_show, + .bypass_wd_timeout_set = ixgbe_bypass_wd_timeout_store, + .bypass_wd_timeout_show = ixgbe_bypass_wd_timeout_show, + .bypass_ver_show = ixgbe_bypass_ver_show, + .bypass_wd_reset = ixgbe_bypass_wd_reset, +#endif /* RTE_NIC_BYPASS */ + .rss_hash_update = ixgbe_dev_rss_hash_update, + .rss_hash_conf_get = ixgbe_dev_rss_hash_conf_get, }; /* @@ -227,11 +327,17 @@ static struct eth_dev_ops ixgbevf_eth_dev_ops = { .link_update = ixgbe_dev_link_update, .stats_get = ixgbevf_dev_stats_get, .stats_reset = ixgbevf_dev_stats_reset, - .dev_close = ixgbevf_dev_stop, - + .dev_close = ixgbevf_dev_close, .dev_infos_get = ixgbe_dev_info_get, + .vlan_filter_set = ixgbevf_vlan_filter_set, + .vlan_strip_queue_set = ixgbevf_vlan_strip_queue_set, + .vlan_offload_set = ixgbevf_vlan_offload_set, .rx_queue_setup = ixgbe_dev_rx_queue_setup, + .rx_queue_release = ixgbe_dev_rx_queue_release, .tx_queue_setup = ixgbe_dev_tx_queue_setup, + .tx_queue_release = ixgbe_dev_tx_queue_release, + .mac_addr_add = ixgbevf_add_mac_addr, + .mac_addr_remove = ixgbevf_remove_mac_addr, }; /** @@ -305,6 +411,35 @@ ixgbe_is_sfp(struct ixgbe_hw *hw) } } +static inline int32_t +ixgbe_pf_reset_hw(struct ixgbe_hw *hw) +{ + uint32_t ctrl_ext; + int32_t status; + + status = ixgbe_reset_hw(hw); + + ctrl_ext = IXGBE_READ_REG(hw, IXGBE_CTRL_EXT); + /* Set PF Reset Done bit so PF/VF Mail Ops can work */ + ctrl_ext |= IXGBE_CTRL_EXT_PFRSTD; + IXGBE_WRITE_REG(hw, IXGBE_CTRL_EXT, ctrl_ext); + IXGBE_WRITE_FLUSH(hw); + + return status; +} + +static inline void +ixgbe_enable_intr(struct rte_eth_dev *dev) +{ + struct ixgbe_interrupt *intr = + IXGBE_DEV_PRIVATE_TO_INTR(dev->data->dev_private); + struct ixgbe_hw *hw = + IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private); + + IXGBE_WRITE_REG(hw, IXGBE_EIMS, intr->mask); + IXGBE_WRITE_FLUSH(hw); +} + /* * This function is based on ixgbe_disable_intr() in ixgbe/ixgbe.h. */ @@ -365,12 +500,12 @@ ixgbe_dev_queue_stats_mapping_set(struct rte_eth_dev *eth_dev, PMD_INIT_LOG(INFO, "Setting port %d, %s queue_id %d to stat index %d\n", (int)(eth_dev->data->port_id), is_rx ? "RX" : "TX", queue_id, stat_idx); - n = queue_id / NB_QMAP_FIELDS_PER_QSM_REG; + n = (uint8_t)(queue_id / NB_QMAP_FIELDS_PER_QSM_REG); if (n >= IXGBE_NB_STAT_MAPPING_REGS) { PMD_INIT_LOG(ERR, "Nb of stat mapping registers exceeded\n"); return -EIO; } - offset = queue_id % NB_QMAP_FIELDS_PER_QSM_REG; + offset = (uint8_t)(queue_id % NB_QMAP_FIELDS_PER_QSM_REG); /* Now clear any previous stat_idx set */ clearing_mask <<= (QSM_REG_NB_BITS_PER_QMAP_FIELD * offset); @@ -424,6 +559,81 @@ ixgbe_restore_statistics_mapping(struct rte_eth_dev * dev) } } +static void +ixgbe_dcb_init(struct ixgbe_hw *hw,struct ixgbe_dcb_config *dcb_config) +{ + uint8_t i; + struct ixgbe_dcb_tc_config *tc; + uint8_t dcb_max_tc = IXGBE_DCB_MAX_TRAFFIC_CLASS; + + dcb_config->num_tcs.pg_tcs = dcb_max_tc; + dcb_config->num_tcs.pfc_tcs = dcb_max_tc; + for (i = 0; i < dcb_max_tc; i++) { + tc = &dcb_config->tc_config[i]; + tc->path[IXGBE_DCB_TX_CONFIG].bwg_id = i; + tc->path[IXGBE_DCB_TX_CONFIG].bwg_percent = + (uint8_t)(100/dcb_max_tc + (i & 1)); + tc->path[IXGBE_DCB_RX_CONFIG].bwg_id = i; + tc->path[IXGBE_DCB_RX_CONFIG].bwg_percent = + (uint8_t)(100/dcb_max_tc + (i & 1)); + tc->pfc = ixgbe_dcb_pfc_disabled; + } + + /* Initialize default user to priority mapping, UPx->TC0 */ + tc = &dcb_config->tc_config[0]; + tc->path[IXGBE_DCB_TX_CONFIG].up_to_tc_bitmap = 0xFF; + tc->path[IXGBE_DCB_RX_CONFIG].up_to_tc_bitmap = 0xFF; + for (i = 0; i< IXGBE_DCB_MAX_BW_GROUP; i++) { + dcb_config->bw_percentage[IXGBE_DCB_TX_CONFIG][i] = 100; + dcb_config->bw_percentage[IXGBE_DCB_RX_CONFIG][i] = 100; + } + dcb_config->rx_pba_cfg = ixgbe_dcb_pba_equal; + dcb_config->pfc_mode_enable = false; + dcb_config->vt_mode = true; + dcb_config->round_robin_enable = false; + /* support all DCB capabilities in 82599 */ + dcb_config->support.capabilities = 0xFF; + + /*we only support 4 Tcs for X540*/ + if (hw->mac.type == ixgbe_mac_X540) { + dcb_config->num_tcs.pg_tcs = 4; + dcb_config->num_tcs.pfc_tcs = 4; + } +} + +/* + * Ensure that all locks are released before first NVM or PHY access + */ +static void +ixgbe_swfw_lock_reset(struct ixgbe_hw *hw) +{ + uint16_t mask; + + /* + * Phy lock should not fail in this early stage. If this is the case, + * it is due to an improper exit of the application. + * So force the release of the faulty lock. Release of common lock + * is done automatically by swfw_sync function. + */ + mask = IXGBE_GSSR_PHY0_SM << hw->bus.func; + if (ixgbe_acquire_swfw_semaphore(hw, mask) < 0) { + DEBUGOUT1("SWFW phy%d lock released", hw->bus.func); + } + ixgbe_release_swfw_semaphore(hw, mask); + + /* + * These ones are more tricky since they are common to all ports; but + * swfw_sync retries last long enough (1s) to be almost sure that if + * lock can not be taken it is due to an improper lock of the + * semaphore. + */ + mask = IXGBE_GSSR_EEP_SM | IXGBE_GSSR_MAC_CSR_SM | IXGBE_GSSR_SW_MNG_SM; + if (ixgbe_acquire_swfw_semaphore(hw, mask) < 0) { + DEBUGOUT("SWFW common locks released"); + } + ixgbe_release_swfw_semaphore(hw, mask); +} + /* * This function is based on code in ixgbe_attach() in ixgbe/ixgbe.c. * It returns 0 on success. @@ -437,6 +647,10 @@ eth_ixgbe_dev_init(__attribute__((unused)) struct eth_driver *eth_drv, IXGBE_DEV_PRIVATE_TO_HW(eth_dev->data->dev_private); struct ixgbe_vfta * shadow_vfta = IXGBE_DEV_PRIVATE_TO_VFTA(eth_dev->data->dev_private); + struct ixgbe_hwstrip *hwstrip = + IXGBE_DEV_PRIVATE_TO_HWSTRIP_BITMAP(eth_dev->data->dev_private); + struct ixgbe_dcb_config *dcb_config = + IXGBE_DEV_PRIVATE_TO_DCB_CFG(eth_dev->data->dev_private); uint32_t ctrl_ext; uint16_t csum; int diag, i; @@ -460,26 +674,42 @@ eth_ixgbe_dev_init(__attribute__((unused)) struct eth_driver *eth_drv, /* Vendor and Device ID need to be set before init of shared code */ hw->device_id = pci_dev->id.device_id; hw->vendor_id = pci_dev->id.vendor_id; - hw->hw_addr = (void *)pci_dev->mem_resource.addr; + hw->hw_addr = (void *)pci_dev->mem_resource[0].addr; +#ifdef RTE_LIBRTE_IXGBE_ALLOW_UNSUPPORTED_SFP + hw->allow_unsupported_sfp = 1; +#endif /* Initialize the shared code */ +#ifdef RTE_NIC_BYPASS + diag = ixgbe_bypass_init_shared_code(hw); +#else diag = ixgbe_init_shared_code(hw); +#endif /* RTE_NIC_BYPASS */ + if (diag != IXGBE_SUCCESS) { PMD_INIT_LOG(ERR, "Shared code init failed: %d", diag); return -EIO; } + /* pick up the PCI bus settings for reporting later */ + ixgbe_get_bus_info(hw); + + /* Unlock any pending hardware semaphore */ + ixgbe_swfw_lock_reset(hw); + + /* Initialize DCB configuration*/ + memset(dcb_config, 0, sizeof(struct ixgbe_dcb_config)); + ixgbe_dcb_init(hw,dcb_config); /* Get Hardware Flow Control setting */ hw->fc.requested_mode = ixgbe_fc_full; hw->fc.current_mode = ixgbe_fc_full; hw->fc.pause_time = IXGBE_FC_PAUSE; - hw->fc.low_water = IXGBE_FC_LO; - for (i = 0; i < MAX_TRAFFIC_CLASS; i++) + for (i = 0; i < IXGBE_DCB_MAX_TRAFFIC_CLASS; i++) { + hw->fc.low_water[i] = IXGBE_FC_LO; hw->fc.high_water[i] = IXGBE_FC_HI; + } hw->fc.send_xon = 1; - ixgbe_disable_intr(hw); - /* Make sure we have a good EEPROM before we read from it */ diag = ixgbe_validate_eeprom_checksum(hw, &csum); if (diag != IXGBE_SUCCESS) { @@ -487,7 +717,11 @@ eth_ixgbe_dev_init(__attribute__((unused)) struct eth_driver *eth_drv, return -EIO; } +#ifdef RTE_NIC_BYPASS + diag = ixgbe_bypass_init_hw(hw); +#else diag = ixgbe_init_hw(hw); +#endif /* RTE_NIC_BYPASS */ /* * Devices with copper phys will fail to initialise if ixgbe_init_hw() @@ -517,8 +751,8 @@ eth_ixgbe_dev_init(__attribute__((unused)) struct eth_driver *eth_drv, return -EIO; } - /* pick up the PCI bus settings for reporting later */ - ixgbe_get_bus_info(hw); + /* disable interrupt */ + ixgbe_disable_intr(hw); /* reset mappings for queue statistics hw counters*/ ixgbe_reset_qstat_mappings(hw); @@ -528,7 +762,8 @@ eth_ixgbe_dev_init(__attribute__((unused)) struct eth_driver *eth_drv, hw->mac.num_rar_entries, 0); if (eth_dev->data->mac_addrs == NULL) { PMD_INIT_LOG(ERR, - "Failed to allocate %d bytes needed to store MAC addresses", + "Failed to allocate %u bytes needed to store " + "MAC addresses", ETHER_ADDR_LEN * hw->mac.num_rar_entries); return -ENOMEM; } @@ -536,13 +771,32 @@ eth_ixgbe_dev_init(__attribute__((unused)) struct eth_driver *eth_drv, ether_addr_copy((struct ether_addr *) hw->mac.perm_addr, ð_dev->data->mac_addrs[0]); + /* Allocate memory for storing hash filter MAC addresses */ + eth_dev->data->hash_mac_addrs = rte_zmalloc("ixgbe", ETHER_ADDR_LEN * + IXGBE_VMDQ_NUM_UC_MAC, 0); + if (eth_dev->data->hash_mac_addrs == NULL) { + PMD_INIT_LOG(ERR, + "Failed to allocate %d bytes needed to store MAC addresses", + ETHER_ADDR_LEN * IXGBE_VMDQ_NUM_UC_MAC); + return -ENOMEM; + } + /* initialize the vfta */ memset(shadow_vfta, 0, sizeof(*shadow_vfta)); - /* let hardware know driver is loaded */ + /* initialize the hw strip bitmap*/ + memset(hwstrip, 0, sizeof(*hwstrip)); + + /* initialize PF if max_vfs not zero */ + ixgbe_pf_host_init(eth_dev); + ctrl_ext = IXGBE_READ_REG(hw, IXGBE_CTRL_EXT); + /* let hardware know driver is loaded */ ctrl_ext |= IXGBE_CTRL_EXT_DRV_LOAD; + /* Set PF Reset Done bit so PF/VF Mail Ops can work */ + ctrl_ext |= IXGBE_CTRL_EXT_PFRSTD; IXGBE_WRITE_REG(hw, IXGBE_CTRL_EXT, ctrl_ext); + IXGBE_WRITE_FLUSH(hw); if (ixgbe_is_sfp(hw) && hw->phy.sfp_type != ixgbe_sfp_type_not_present) PMD_INIT_LOG(DEBUG, @@ -560,9 +814,57 @@ eth_ixgbe_dev_init(__attribute__((unused)) struct eth_driver *eth_drv, rte_intr_callback_register(&(pci_dev->intr_handle), ixgbe_dev_interrupt_handler, (void *)eth_dev); + /* enable uio intr after callback register */ + rte_intr_enable(&(pci_dev->intr_handle)); + + /* enable support intr */ + ixgbe_enable_intr(eth_dev); + return 0; } + +/* + * Negotiate mailbox API version with the PF. + * After reset API version is always set to the basic one (ixgbe_mbox_api_10). + * Then we try to negotiate starting with the most recent one. + * If all negotiation attempts fail, then we will proceed with + * the default one (ixgbe_mbox_api_10). + */ +static void +ixgbevf_negotiate_api(struct ixgbe_hw *hw) +{ + int32_t i; + + /* start with highest supported, proceed down */ + static const enum ixgbe_pfvf_api_rev sup_ver[] = { + ixgbe_mbox_api_11, + ixgbe_mbox_api_10, + }; + + for (i = 0; + i != RTE_DIM(sup_ver) && + ixgbevf_negotiate_api_version(hw, sup_ver[i]) != 0; + i++) + ; +} + +static void +generate_random_mac_addr(struct ether_addr *mac_addr) +{ + uint64_t random; + + /* Set Organizationally Unique Identifier (OUI) prefix. */ + mac_addr->addr_bytes[0] = 0x00; + mac_addr->addr_bytes[1] = 0x09; + mac_addr->addr_bytes[2] = 0xC0; + /* Force indication of locally assigned MAC address. */ + mac_addr->addr_bytes[0] |= ETHER_LOCAL_ADMIN_ADDR; + /* Generate the last 3 bytes of the MAC address with a random number. */ + random = rte_rand(); + memcpy(&mac_addr->addr_bytes[3], &random, 3); +} + /* * Virtual Function device init */ @@ -570,18 +872,43 @@ static int eth_ixgbevf_dev_init(__attribute__((unused)) struct eth_driver *eth_drv, struct rte_eth_dev *eth_dev) { - struct rte_pci_device *pci_dev; - struct ixgbe_hw *hw = IXGBE_DEV_PRIVATE_TO_HW(eth_dev->data->dev_private); int diag; + uint32_t tc, tcs; + struct rte_pci_device *pci_dev; + struct ixgbe_hw *hw = + IXGBE_DEV_PRIVATE_TO_HW(eth_dev->data->dev_private); + struct ixgbe_vfta * shadow_vfta = + IXGBE_DEV_PRIVATE_TO_VFTA(eth_dev->data->dev_private); + struct ixgbe_hwstrip *hwstrip = + IXGBE_DEV_PRIVATE_TO_HWSTRIP_BITMAP(eth_dev->data->dev_private); + struct ether_addr *perm_addr = (struct ether_addr *) hw->mac.perm_addr; PMD_INIT_LOG(DEBUG, "eth_ixgbevf_dev_init"); eth_dev->dev_ops = &ixgbevf_eth_dev_ops; + eth_dev->rx_pkt_burst = &ixgbe_recv_pkts; + eth_dev->tx_pkt_burst = &ixgbe_xmit_pkts; + + /* for secondary processes, we don't initialise any further as primary + * 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_scattered_pkts; + return 0; + } + pci_dev = eth_dev->pci_dev; hw->device_id = pci_dev->id.device_id; hw->vendor_id = pci_dev->id.vendor_id; - hw->hw_addr = (void *)pci_dev->mem_resource.addr; + hw->hw_addr = (void *)pci_dev->mem_resource[0].addr; + + /* initialize the vfta */ + memset(shadow_vfta, 0, sizeof(*shadow_vfta)); + + /* initialize the hw strip bitmap*/ + memset(hwstrip, 0, sizeof(*hwstrip)); /* Initialize the shared code */ diag = ixgbe_init_shared_code(hw); @@ -596,21 +923,59 @@ eth_ixgbevf_dev_init(__attribute__((unused)) struct eth_driver *eth_drv, /* Disable the interrupts for VF */ ixgbevf_intr_disable(hw); - hw->mac.num_rar_entries = hw->mac.max_rx_queues; + hw->mac.num_rar_entries = 128; /* The MAX of the underlying PF */ diag = hw->mac.ops.reset_hw(hw); + /* + * The VF reset operation returns the IXGBE_ERR_INVALID_MAC_ADDR when + * the underlying PF driver has not assigned a MAC address to the VF. + * In this case, assign a random MAC address. + */ + if ((diag != IXGBE_SUCCESS) && (diag != IXGBE_ERR_INVALID_MAC_ADDR)) { + PMD_INIT_LOG(ERR, "VF Initialization Failure: %d", diag); + return (diag); + } + + /* negotiate mailbox API version to use with the PF. */ + ixgbevf_negotiate_api(hw); + + /* Get Rx/Tx queue count via mailbox, which is ready after reset_hw */ + ixgbevf_get_queues(hw, &tcs, &tc); + /* Allocate memory for storing MAC addresses */ eth_dev->data->mac_addrs = rte_zmalloc("ixgbevf", ETHER_ADDR_LEN * hw->mac.num_rar_entries, 0); if (eth_dev->data->mac_addrs == NULL) { PMD_INIT_LOG(ERR, - "Failed to allocate %d bytes needed to store MAC addresses", + "Failed to allocate %u bytes needed to store " + "MAC addresses", ETHER_ADDR_LEN * hw->mac.num_rar_entries); return -ENOMEM; } + + /* Generate a random MAC address, if none was assigned by PF. */ + if (is_zero_ether_addr(perm_addr)) { + generate_random_mac_addr(perm_addr); + diag = ixgbe_set_rar_vf(hw, 1, perm_addr->addr_bytes, 0, 1); + if (diag) { + rte_free(eth_dev->data->mac_addrs); + eth_dev->data->mac_addrs = NULL; + return diag; + } + RTE_LOG(INFO, PMD, + "\tVF MAC address not assigned by Host PF\n" + "\tAssign randomly generated MAC address " + "%02x:%02x:%02x:%02x:%02x:%02x\n", + perm_addr->addr_bytes[0], + perm_addr->addr_bytes[1], + perm_addr->addr_bytes[2], + perm_addr->addr_bytes[3], + perm_addr->addr_bytes[4], + perm_addr->addr_bytes[5]); + } + /* Copy the permanent MAC address */ - ether_addr_copy((struct ether_addr *) hw->mac.perm_addr, - ð_dev->data->mac_addrs[0]); + ether_addr_copy(perm_addr, ð_dev->data->mac_addrs[0]); /* reset the hardware with the new settings */ diag = hw->mac.ops.start_hw(hw); @@ -620,7 +985,7 @@ eth_ixgbevf_dev_init(__attribute__((unused)) struct eth_driver *eth_drv, default: PMD_INIT_LOG(ERR, "VF Initialization Failure: %d", diag); - return (diag); + return (-EIO); } PMD_INIT_LOG(DEBUG, "\nport %d vendorID=0x%x deviceID=0x%x mac.type=%s\n", @@ -658,8 +1023,8 @@ static struct eth_driver rte_ixgbevf_pmd = { * Invoked once at EAL init time. * Register itself as the [Poll Mode] Driver of PCI IXGBE devices. */ -int -rte_ixgbe_pmd_init(void) +static int +rte_ixgbe_pmd_init(const char *name __rte_unused, const char *params __rte_unused) { PMD_INIT_FUNC_TRACE(); @@ -672,8 +1037,8 @@ rte_ixgbe_pmd_init(void) * Invoked one at EAL init time. * Register itself as the [Virtual Poll Mode] Driver of PCI niantic devices. */ -int -rte_ixgbevf_pmd_init(void) +static int +rte_ixgbevf_pmd_init(const char *name __rte_unused, const char *param __rte_unused) { DEBUGFUNC("rte_ixgbevf_pmd_init"); @@ -681,7 +1046,7 @@ rte_ixgbevf_pmd_init(void) return (0); } -static void +static int ixgbe_vlan_filter_set(struct rte_eth_dev *dev, uint16_t vlan_id, int on) { struct ixgbe_hw *hw = @@ -703,16 +1068,35 @@ ixgbe_vlan_filter_set(struct rte_eth_dev *dev, uint16_t vlan_id, int on) /* update local VFTA copy */ shadow_vfta->vfta[vid_idx] = vfta; + + return 0; +} + +static void +ixgbe_vlan_strip_queue_set(struct rte_eth_dev *dev, uint16_t queue, int on) +{ + if (on) + ixgbe_vlan_hw_strip_enable(dev, queue); + else + ixgbe_vlan_hw_strip_disable(dev, queue); } static void -ixgbe_vlan_hw_support_disable(struct rte_eth_dev *dev) +ixgbe_vlan_tpid_set(struct rte_eth_dev *dev, uint16_t tpid) +{ + struct ixgbe_hw *hw = + IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private); + + /* Only the high 16-bits is valid */ + IXGBE_WRITE_REG(hw, IXGBE_EXVET, tpid << 16); +} + +void +ixgbe_vlan_hw_filter_disable(struct rte_eth_dev *dev) { struct ixgbe_hw *hw = IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private); uint32_t vlnctrl; - uint32_t rxdctl; - uint16_t i; PMD_INIT_FUNC_TRACE(); @@ -720,28 +1104,17 @@ ixgbe_vlan_hw_support_disable(struct rte_eth_dev *dev) vlnctrl = IXGBE_READ_REG(hw, IXGBE_VLNCTRL); vlnctrl &= ~IXGBE_VLNCTRL_VFE; - if (hw->mac.type == ixgbe_mac_82598EB) - vlnctrl &= ~IXGBE_VLNCTRL_VME; - else { - /* On 82599 the VLAN enable is per/queue in RXDCTL */ - for (i = 0; i < dev->data->nb_rx_queues; i++) { - rxdctl = IXGBE_READ_REG(hw, IXGBE_RXDCTL(i)); - rxdctl &= ~IXGBE_RXDCTL_VME; - IXGBE_WRITE_REG(hw, IXGBE_RXDCTL(i), rxdctl); - } - } IXGBE_WRITE_REG(hw, IXGBE_VLNCTRL, vlnctrl); } -static void -ixgbe_vlan_hw_support_enable(struct rte_eth_dev *dev) +void +ixgbe_vlan_hw_filter_enable(struct rte_eth_dev *dev) { struct ixgbe_hw *hw = IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private); struct ixgbe_vfta * shadow_vfta = IXGBE_DEV_PRIVATE_TO_VFTA(dev->data->dev_private); uint32_t vlnctrl; - uint32_t rxdctl; uint16_t i; PMD_INIT_FUNC_TRACE(); @@ -751,16 +1124,6 @@ ixgbe_vlan_hw_support_enable(struct rte_eth_dev *dev) vlnctrl &= ~IXGBE_VLNCTRL_CFIEN; vlnctrl |= IXGBE_VLNCTRL_VFE; - if (hw->mac.type == ixgbe_mac_82598EB) - vlnctrl |= IXGBE_VLNCTRL_VME; - else { - /* On 82599 the VLAN enable is per/queue in RXDCTL */ - for (i = 0; i < dev->data->nb_rx_queues; i++) { - rxdctl = IXGBE_READ_REG(hw, IXGBE_RXDCTL(i)); - rxdctl |= IXGBE_RXDCTL_VME; - IXGBE_WRITE_REG(hw, IXGBE_RXDCTL(i), rxdctl); - } - } IXGBE_WRITE_REG(hw, IXGBE_VLNCTRL, vlnctrl); /* write whatever is in local vfta copy */ @@ -768,96 +1131,290 @@ ixgbe_vlan_hw_support_enable(struct rte_eth_dev *dev) IXGBE_WRITE_REG(hw, IXGBE_VFTA(i), shadow_vfta->vfta[i]); } -static int -ixgbe_dev_configure(struct rte_eth_dev *dev, uint16_t nb_rx_q, uint16_t nb_tx_q) +static void +ixgbe_vlan_hw_strip_bitmap_set(struct rte_eth_dev *dev, uint16_t queue, bool on) { - struct ixgbe_interrupt *intr = - IXGBE_DEV_PRIVATE_TO_INTR(dev->data->dev_private); - int diag; + struct ixgbe_hwstrip *hwstrip = + IXGBE_DEV_PRIVATE_TO_HWSTRIP_BITMAP(dev->data->dev_private); + + if(queue >= IXGBE_MAX_RX_QUEUE_NUM) + return; + + if (on) + IXGBE_SET_HWSTRIP(hwstrip, queue); + else + IXGBE_CLEAR_HWSTRIP(hwstrip, queue); +} + +static void +ixgbe_vlan_hw_strip_disable(struct rte_eth_dev *dev, uint16_t queue) +{ + struct ixgbe_hw *hw = + IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private); + uint32_t ctrl; PMD_INIT_FUNC_TRACE(); - /* Allocate the array of pointers to RX queue structures */ - diag = ixgbe_dev_rx_queue_alloc(dev, nb_rx_q); - if (diag != 0) { - PMD_INIT_LOG(ERR, "ethdev port_id=%d allocation of array of %d" - "pointers to RX queues failed", dev->data->port_id, - nb_rx_q); - return diag; + if (hw->mac.type == ixgbe_mac_82598EB) { + /* No queue level support */ + PMD_INIT_LOG(INFO, "82598EB not support queue level hw strip"); + return; } - - /* Allocate the array of pointers to TX queue structures */ - diag = ixgbe_dev_tx_queue_alloc(dev, nb_tx_q); - if (diag != 0) { - PMD_INIT_LOG(ERR, "ethdev port_id=%d allocation of array of %d" - "pointers to TX queues failed", dev->data->port_id, - nb_tx_q); - return diag; + else { + /* Other 10G NIC, the VLAN strip can be setup per queue in RXDCTL */ + ctrl = IXGBE_READ_REG(hw, IXGBE_RXDCTL(queue)); + ctrl &= ~IXGBE_RXDCTL_VME; + IXGBE_WRITE_REG(hw, IXGBE_RXDCTL(queue), ctrl); } + /* record those setting for HW strip per queue */ + ixgbe_vlan_hw_strip_bitmap_set(dev, queue, 0); +} - /* set flag to update link status after init */ - intr->flags |= IXGBE_FLAG_NEED_LINK_UPDATE; +static void +ixgbe_vlan_hw_strip_enable(struct rte_eth_dev *dev, uint16_t queue) +{ + struct ixgbe_hw *hw = + IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private); + uint32_t ctrl; - return 0; + PMD_INIT_FUNC_TRACE(); + + if (hw->mac.type == ixgbe_mac_82598EB) { + /* No queue level supported */ + PMD_INIT_LOG(INFO, "82598EB not support queue level hw strip"); + return; + } + else { + /* Other 10G NIC, the VLAN strip can be setup per queue in RXDCTL */ + ctrl = IXGBE_READ_REG(hw, IXGBE_RXDCTL(queue)); + ctrl |= IXGBE_RXDCTL_VME; + IXGBE_WRITE_REG(hw, IXGBE_RXDCTL(queue), ctrl); + } + /* record those setting for HW strip per queue */ + ixgbe_vlan_hw_strip_bitmap_set(dev, queue, 1); } -/* - * Configure device link speed and setup link. - * It returns 0 on success. - */ -static int -ixgbe_dev_start(struct rte_eth_dev *dev) +void +ixgbe_vlan_hw_strip_disable_all(struct rte_eth_dev *dev) { struct ixgbe_hw *hw = IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private); - int err, link_up = 0, negotiate = 0; - uint32_t speed = 0; + uint32_t ctrl; + uint16_t i; PMD_INIT_FUNC_TRACE(); - /* IXGBE devices don't support half duplex */ - if ((dev->data->dev_conf.link_duplex != ETH_LINK_AUTONEG_DUPLEX) && - (dev->data->dev_conf.link_duplex != ETH_LINK_FULL_DUPLEX)) { - PMD_INIT_LOG(ERR, "Invalid link_duplex (%u) for port %u\n", - dev->data->dev_conf.link_duplex, - dev->data->port_id); - return -EINVAL; + if (hw->mac.type == ixgbe_mac_82598EB) { + ctrl = IXGBE_READ_REG(hw, IXGBE_VLNCTRL); + ctrl &= ~IXGBE_VLNCTRL_VME; + IXGBE_WRITE_REG(hw, IXGBE_VLNCTRL, ctrl); } + else { + /* Other 10G NIC, the VLAN strip can be setup per queue in RXDCTL */ + for (i = 0; i < dev->data->nb_rx_queues; i++) { + ctrl = IXGBE_READ_REG(hw, IXGBE_RXDCTL(i)); + ctrl &= ~IXGBE_RXDCTL_VME; + IXGBE_WRITE_REG(hw, IXGBE_RXDCTL(i), ctrl); - /* stop adapter */ - hw->adapter_stopped = FALSE; - ixgbe_stop_adapter(hw); + /* record those setting for HW strip per queue */ + ixgbe_vlan_hw_strip_bitmap_set(dev, i, 0); + } + } +} - /* reinitialize adapter - * this calls reset and start */ - ixgbe_init_hw(hw); +void +ixgbe_vlan_hw_strip_enable_all(struct rte_eth_dev *dev) +{ + struct ixgbe_hw *hw = + IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private); + uint32_t ctrl; + uint16_t i; - /* initialize transmission unit */ - ixgbe_dev_tx_init(dev); + PMD_INIT_FUNC_TRACE(); - /* This can fail when allocating mbufs for descriptor rings */ - err = ixgbe_dev_rx_init(dev); - if (err) { - PMD_INIT_LOG(ERR, "Unable to initialize RX hardware\n"); - return err; + if (hw->mac.type == ixgbe_mac_82598EB) { + ctrl = IXGBE_READ_REG(hw, IXGBE_VLNCTRL); + ctrl |= IXGBE_VLNCTRL_VME; + IXGBE_WRITE_REG(hw, IXGBE_VLNCTRL, ctrl); } + else { + /* Other 10G NIC, the VLAN strip can be setup per queue in RXDCTL */ + for (i = 0; i < dev->data->nb_rx_queues; i++) { + ctrl = IXGBE_READ_REG(hw, IXGBE_RXDCTL(i)); + ctrl |= IXGBE_RXDCTL_VME; + IXGBE_WRITE_REG(hw, IXGBE_RXDCTL(i), ctrl); - ixgbe_dev_rxtx_start(dev); - - if (ixgbe_is_sfp(hw) && hw->phy.multispeed_fiber) { - err = hw->mac.ops.setup_sfp(hw); - if (err) - goto error; + /* record those setting for HW strip per queue */ + ixgbe_vlan_hw_strip_bitmap_set(dev, i, 1); + } } +} - /* Turn on the laser */ - if (hw->phy.multispeed_fiber) - ixgbe_enable_tx_laser(hw); +static void +ixgbe_vlan_hw_extend_disable(struct rte_eth_dev *dev) +{ + struct ixgbe_hw *hw = + IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private); + uint32_t ctrl; - err = ixgbe_check_link(hw, &speed, &link_up, 0); - if (err) - goto error; - err = ixgbe_get_link_capabilities(hw, &speed, &negotiate); + PMD_INIT_FUNC_TRACE(); + + /* DMATXCTRL: Geric Double VLAN Disable */ + ctrl = IXGBE_READ_REG(hw, IXGBE_DMATXCTL); + ctrl &= ~IXGBE_DMATXCTL_GDV; + IXGBE_WRITE_REG(hw, IXGBE_DMATXCTL, ctrl); + + /* CTRL_EXT: Global Double VLAN Disable */ + ctrl = IXGBE_READ_REG(hw, IXGBE_CTRL_EXT); + ctrl &= ~IXGBE_EXTENDED_VLAN; + IXGBE_WRITE_REG(hw, IXGBE_CTRL_EXT, ctrl); + +} + +static void +ixgbe_vlan_hw_extend_enable(struct rte_eth_dev *dev) +{ + struct ixgbe_hw *hw = + IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private); + uint32_t ctrl; + + PMD_INIT_FUNC_TRACE(); + + /* DMATXCTRL: Geric Double VLAN Enable */ + ctrl = IXGBE_READ_REG(hw, IXGBE_DMATXCTL); + ctrl |= IXGBE_DMATXCTL_GDV; + IXGBE_WRITE_REG(hw, IXGBE_DMATXCTL, ctrl); + + /* CTRL_EXT: Global Double VLAN Enable */ + ctrl = IXGBE_READ_REG(hw, IXGBE_CTRL_EXT); + ctrl |= IXGBE_EXTENDED_VLAN; + IXGBE_WRITE_REG(hw, IXGBE_CTRL_EXT, ctrl); + + /* + * VET EXT field in the EXVET register = 0x8100 by default + * So no need to change. Same to VT field of DMATXCTL register + */ +} + +static void +ixgbe_vlan_offload_set(struct rte_eth_dev *dev, int mask) +{ + if(mask & ETH_VLAN_STRIP_MASK){ + if (dev->data->dev_conf.rxmode.hw_vlan_strip) + ixgbe_vlan_hw_strip_enable_all(dev); + else + ixgbe_vlan_hw_strip_disable_all(dev); + } + + if(mask & ETH_VLAN_FILTER_MASK){ + if (dev->data->dev_conf.rxmode.hw_vlan_filter) + ixgbe_vlan_hw_filter_enable(dev); + else + ixgbe_vlan_hw_filter_disable(dev); + } + + if(mask & ETH_VLAN_EXTEND_MASK){ + if (dev->data->dev_conf.rxmode.hw_vlan_extend) + ixgbe_vlan_hw_extend_enable(dev); + else + ixgbe_vlan_hw_extend_disable(dev); + } +} + +static void +ixgbe_vmdq_vlan_hw_filter_enable(struct rte_eth_dev *dev) +{ + struct ixgbe_hw *hw = + IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private); + /* VLNCTRL: enable vlan filtering and allow all vlan tags through */ + uint32_t vlanctrl = IXGBE_READ_REG(hw, IXGBE_VLNCTRL); + vlanctrl |= IXGBE_VLNCTRL_VFE ; /* enable vlan filters */ + IXGBE_WRITE_REG(hw, IXGBE_VLNCTRL, vlanctrl); +} + +static int +ixgbe_dev_configure(struct rte_eth_dev *dev) +{ + struct ixgbe_interrupt *intr = + IXGBE_DEV_PRIVATE_TO_INTR(dev->data->dev_private); + + PMD_INIT_FUNC_TRACE(); + + /* set flag to update link status after init */ + intr->flags |= IXGBE_FLAG_NEED_LINK_UPDATE; + + return 0; +} + +/* + * Configure device link speed and setup link. + * It returns 0 on success. + */ +static int +ixgbe_dev_start(struct rte_eth_dev *dev) +{ + struct ixgbe_hw *hw = + IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private); + int err, link_up = 0, negotiate = 0; + uint32_t speed = 0; + int mask = 0; + int status; + + PMD_INIT_FUNC_TRACE(); + + /* IXGBE devices don't support half duplex */ + if ((dev->data->dev_conf.link_duplex != ETH_LINK_AUTONEG_DUPLEX) && + (dev->data->dev_conf.link_duplex != ETH_LINK_FULL_DUPLEX)) { + PMD_INIT_LOG(ERR, "Invalid link_duplex (%hu) for port %hhu\n", + dev->data->dev_conf.link_duplex, + dev->data->port_id); + return -EINVAL; + } + + /* stop adapter */ + hw->adapter_stopped = FALSE; + ixgbe_stop_adapter(hw); + + /* reinitialize adapter + * this calls reset and start */ + status = ixgbe_pf_reset_hw(hw); + if (status != 0) + return -1; + hw->mac.ops.start_hw(hw); + + /* configure PF module if SRIOV enabled */ + ixgbe_pf_host_configure(dev); + + /* initialize transmission unit */ + ixgbe_dev_tx_init(dev); + + /* This can fail when allocating mbufs for descriptor rings */ + err = ixgbe_dev_rx_init(dev); + if (err) { + PMD_INIT_LOG(ERR, "Unable to initialize RX hardware\n"); + goto error; + } + + ixgbe_dev_rxtx_start(dev); + + if (ixgbe_is_sfp(hw) && hw->phy.multispeed_fiber) { + err = hw->mac.ops.setup_sfp(hw); + if (err) + goto error; + } + + /* Turn on the laser */ + ixgbe_enable_tx_laser(hw); + + /* Skip link setup if loopback mode is enabled for 82599. */ + if (hw->mac.type == ixgbe_mac_82599EB && + dev->data->dev_conf.lpbk_mode == IXGBE_LPBK_82599_TX_RX) + goto skip_link_setup; + + err = ixgbe_check_link(hw, &speed, &link_up, 0); + if (err) + goto error; + err = ixgbe_get_link_capabilities(hw, &speed, &negotiate); if (err) goto error; @@ -881,30 +1438,36 @@ ixgbe_dev_start(struct rte_eth_dev *dev) speed = IXGBE_LINK_SPEED_10GB_FULL; break; default: - PMD_INIT_LOG(ERR, "Invalid link_speed (%u) for port %u\n", - dev->data->dev_conf.link_speed, dev->data->port_id); - return -EINVAL; + PMD_INIT_LOG(ERR, "Invalid link_speed (%hu) for port %hhu\n", + dev->data->dev_conf.link_speed, + dev->data->port_id); + goto error; } err = ixgbe_setup_link(hw, speed, negotiate, link_up); if (err) goto error; +skip_link_setup: + /* check if lsc interrupt is enabled */ - if (dev->data->dev_conf.intr_conf.lsc != 0) { - err = ixgbe_dev_interrupt_setup(dev); - if (err) - goto error; + if (dev->data->dev_conf.intr_conf.lsc != 0) + ixgbe_dev_lsc_interrupt_setup(dev); + + /* resume enabled intr since hw reset */ + ixgbe_enable_intr(dev); + + mask = ETH_VLAN_STRIP_MASK | ETH_VLAN_FILTER_MASK | \ + ETH_VLAN_EXTEND_MASK; + ixgbe_vlan_offload_set(dev, mask); + + if (dev->data->dev_conf.rxmode.mq_mode == ETH_MQ_RX_VMDQ_ONLY) { + /* Enable vlan filtering for VMDq */ + ixgbe_vmdq_vlan_hw_filter_enable(dev); } - /* - * If VLAN filtering is enabled, set up VLAN tag offload and filtering - * and restore VFTA. - */ - if (dev->data->dev_conf.rxmode.hw_vlan_filter) - ixgbe_vlan_hw_support_enable(dev); - else - ixgbe_vlan_hw_support_disable(dev); + /* Configure DCB hw */ + ixgbe_configure_dcb(dev); if (dev->data->dev_conf.fdir_conf.mode != RTE_FDIR_MODE_NONE) { err = ixgbe_fdir_configure(dev); @@ -918,6 +1481,7 @@ ixgbe_dev_start(struct rte_eth_dev *dev) error: PMD_INIT_LOG(ERR, "failure in ixgbe_dev_start(): %d", err); + ixgbe_dev_clear_queues(dev); return -EIO; } @@ -930,6 +1494,9 @@ ixgbe_dev_stop(struct rte_eth_dev *dev) struct rte_eth_link link; struct ixgbe_hw *hw = IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private); + struct ixgbe_vf_info *vfinfo = + *IXGBE_DEV_PRIVATE_TO_P_VFDATA(dev->data->dev_private); + int vf; PMD_INIT_FUNC_TRACE(); @@ -937,15 +1504,18 @@ ixgbe_dev_stop(struct rte_eth_dev *dev) ixgbe_disable_intr(hw); /* reset the NIC */ - ixgbe_reset_hw(hw); + ixgbe_pf_reset_hw(hw); hw->adapter_stopped = FALSE; /* stop adapter */ ixgbe_stop_adapter(hw); + for (vf = 0; vfinfo != NULL && + vf < dev->pci_dev->max_vfs; vf++) + vfinfo[vf].clear_to_send = false; + /* Turn off the laser */ - if (hw->phy.multispeed_fiber) - ixgbe_disable_tx_laser(hw); + ixgbe_disable_tx_laser(hw); ixgbe_dev_clear_queues(dev); @@ -965,8 +1535,7 @@ ixgbe_dev_close(struct rte_eth_dev *dev) PMD_INIT_FUNC_TRACE(); - ixgbe_reset_hw(hw); - + ixgbe_pf_reset_hw(hw); ixgbe_dev_stop(dev); hw->adapter_stopped = 1; @@ -1043,12 +1612,12 @@ ixgbe_dev_stats_get(struct rte_eth_dev *dev, struct rte_eth_stats *stats) hw_stats->gprc += IXGBE_READ_REG(hw, IXGBE_GPRC); if (hw->mac.type != ixgbe_mac_82598EB) { - hw_stats->gorc += IXGBE_READ_REG(hw, IXGBE_GORCL) + - ((u64)IXGBE_READ_REG(hw, IXGBE_GORCH) << 32); - hw_stats->gotc += IXGBE_READ_REG(hw, IXGBE_GOTCL) + - ((u64)IXGBE_READ_REG(hw, IXGBE_GOTCH) << 32); - hw_stats->tor += IXGBE_READ_REG(hw, IXGBE_TORL) + - ((u64)IXGBE_READ_REG(hw, IXGBE_TORH) << 32); + hw_stats->gorc += IXGBE_READ_REG(hw, IXGBE_GORCL); + hw_stats->gorc += ((u64)IXGBE_READ_REG(hw, IXGBE_GORCH) << 32); + hw_stats->gotc += IXGBE_READ_REG(hw, IXGBE_GOTCL); + hw_stats->gotc += ((u64)IXGBE_READ_REG(hw, IXGBE_GOTCH) << 32); + hw_stats->tor += IXGBE_READ_REG(hw, IXGBE_TORL); + hw_stats->tor += ((u64)IXGBE_READ_REG(hw, IXGBE_TORH) << 32); hw_stats->lxonrxc += IXGBE_READ_REG(hw, IXGBE_LXONRXCNT); hw_stats->lxoffrxc += IXGBE_READ_REG(hw, IXGBE_LXOFFRXCNT); } else { @@ -1142,6 +1711,12 @@ ixgbe_dev_stats_get(struct rte_eth_dev *dev, struct rte_eth_stats *stats) stats->oerrors = 0; + /* XON/XOFF pause frames */ + stats->tx_pause_xon = hw_stats->lxontxc; + stats->rx_pause_xon = hw_stats->lxonrxc; + stats->tx_pause_xoff = hw_stats->lxofftxc; + stats->rx_pause_xoff = hw_stats->lxoffrxc; + /* Flow Director Stats registers */ hw_stats->fdirmatch += IXGBE_READ_REG(hw, IXGBE_FDIRMATCH); hw_stats->fdirmiss += IXGBE_READ_REG(hw, IXGBE_FDIRMISS); @@ -1223,11 +1798,28 @@ 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); - dev_info->max_rx_queues = hw->mac.max_rx_queues; - dev_info->max_tx_queues = hw->mac.max_tx_queues; + dev_info->max_rx_queues = (uint16_t)hw->mac.max_rx_queues; + dev_info->max_tx_queues = (uint16_t)hw->mac.max_tx_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; + dev_info->max_hash_mac_addrs = IXGBE_VMDQ_NUM_UC_MAC; + dev_info->max_vfs = dev->pci_dev->max_vfs; + if (hw->mac.type == ixgbe_mac_82598EB) + dev_info->max_vmdq_pools = ETH_16_POOLS; + else + dev_info->max_vmdq_pools = ETH_64_POOLS; + dev_info->rx_offload_capa = + DEV_RX_OFFLOAD_VLAN_STRIP | + DEV_RX_OFFLOAD_IPV4_CKSUM | + DEV_RX_OFFLOAD_UDP_CKSUM | + DEV_RX_OFFLOAD_TCP_CKSUM; + dev_info->tx_offload_capa = + DEV_TX_OFFLOAD_VLAN_INSERT | + DEV_TX_OFFLOAD_IPV4_CKSUM | + DEV_TX_OFFLOAD_UDP_CKSUM | + DEV_TX_OFFLOAD_TCP_CKSUM | + DEV_TX_OFFLOAD_SCTP_CKSUM; } /* return 0 means link status changed, -1 means not changed */ @@ -1359,14 +1951,13 @@ ixgbe_dev_allmulticast_disable(struct rte_eth_dev *dev) * - On failure, a negative value. */ static int -ixgbe_dev_interrupt_setup(struct rte_eth_dev *dev) +ixgbe_dev_lsc_interrupt_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); ixgbe_dev_link_status_print(dev); - IXGBE_WRITE_REG(hw, IXGBE_EIMS, IXGBE_EICR_LSC); - IXGBE_WRITE_FLUSH(hw); - rte_intr_enable(&(dev->pci_dev->intr_handle)); + intr->mask |= IXGBE_EICR_LSC; return 0; } @@ -1389,17 +1980,22 @@ ixgbe_dev_interrupt_get_status(struct rte_eth_dev *dev) struct ixgbe_interrupt *intr = IXGBE_DEV_PRIVATE_TO_INTR(dev->data->dev_private); - IXGBE_WRITE_REG(hw, IXGBE_EIMC, IXGBE_EICR_LSC); - IXGBE_WRITE_FLUSH(hw); + /* clear all cause mask */ + ixgbe_disable_intr(hw); /* read-on-clear nic registers here */ eicr = IXGBE_READ_REG(hw, IXGBE_EICR); - PMD_INIT_LOG(INFO, "eicr %x", eicr); + PMD_DRV_LOG(INFO, "eicr %x", eicr); + + intr->flags = 0; if (eicr & IXGBE_EICR_LSC) { /* set flag for async link update */ intr->flags |= IXGBE_FLAG_NEED_LINK_UPDATE; } + if (eicr & IXGBE_EICR_MAILBOX) + intr->flags |= IXGBE_FLAG_MAILBOX; + return 0; } @@ -1438,7 +2034,7 @@ ixgbe_dev_link_status_print(struct rte_eth_dev *dev) } /* - * It executes link_update after knowing an interrupt occured. + * It executes link_update after knowing an interrupt occurred. * * @param dev * Pointer to struct rte_eth_dev. @@ -1452,11 +2048,48 @@ ixgbe_dev_interrupt_action(struct rte_eth_dev *dev) { struct ixgbe_interrupt *intr = IXGBE_DEV_PRIVATE_TO_INTR(dev->data->dev_private); + int64_t timeout; + struct rte_eth_link link; + int intr_enable_delay = false; - if (!(intr->flags & IXGBE_FLAG_NEED_LINK_UPDATE)) { - return -1; + PMD_DRV_LOG(DEBUG, "intr action type %d\n", intr->flags); + + if (intr->flags & IXGBE_FLAG_MAILBOX) { + ixgbe_pf_mbx_process(dev); + intr->flags &= ~IXGBE_FLAG_MAILBOX; + } + + if (intr->flags & IXGBE_FLAG_NEED_LINK_UPDATE) { + /* get the link status before link update, for predicting later */ + memset(&link, 0, sizeof(link)); + rte_ixgbe_dev_atomic_read_link_status(dev, &link); + + ixgbe_dev_link_update(dev, 0); + + /* likely to up */ + if (!link.link_status) + /* handle it 1 sec later, wait it being stable */ + timeout = IXGBE_LINK_UP_CHECK_TIMEOUT; + /* likely to down */ + else + /* handle it 4 sec later, wait it being stable */ + timeout = IXGBE_LINK_DOWN_CHECK_TIMEOUT; + + ixgbe_dev_link_status_print(dev); + + intr_enable_delay = true; } - ixgbe_dev_link_update(dev, 0); + + if (intr_enable_delay) { + if (rte_eal_alarm_set(timeout * 1000, + ixgbe_dev_interrupt_delayed_handler, (void*)dev) < 0) + PMD_DRV_LOG(ERR, "Error setting alarm"); + } else { + PMD_DRV_LOG(DEBUG, "enable intr immediately"); + ixgbe_enable_intr(dev); + rte_intr_enable(&(dev->pci_dev->intr_handle)); + } + return 0; } @@ -1483,17 +2116,22 @@ ixgbe_dev_interrupt_delayed_handler(void *param) IXGBE_DEV_PRIVATE_TO_INTR(dev->data->dev_private); struct ixgbe_hw *hw = IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private); + uint32_t eicr; + + eicr = IXGBE_READ_REG(hw, IXGBE_EICR); + if (eicr & IXGBE_EICR_MAILBOX) + ixgbe_pf_mbx_process(dev); - IXGBE_READ_REG(hw, IXGBE_EICR); - ixgbe_dev_interrupt_action(dev); if (intr->flags & IXGBE_FLAG_NEED_LINK_UPDATE) { + ixgbe_dev_link_update(dev, 0); intr->flags &= ~IXGBE_FLAG_NEED_LINK_UPDATE; - rte_intr_enable(&(dev->pci_dev->intr_handle)); - IXGBE_WRITE_REG(hw, IXGBE_EIMS, IXGBE_EICR_LSC); - IXGBE_WRITE_FLUSH(hw); ixgbe_dev_link_status_print(dev); _rte_eth_dev_callback_process(dev, RTE_ETH_EVENT_INTR_LSC); } + + PMD_DRV_LOG(DEBUG, "enable intr in delayed handler S[%08x]\n", eicr); + ixgbe_enable_intr(dev); + rte_intr_enable(&(dev->pci_dev->intr_handle)); } /** @@ -1509,36 +2147,12 @@ ixgbe_dev_interrupt_delayed_handler(void *param) * void */ static void -ixgbe_dev_interrupt_handler(struct rte_intr_handle *handle, void *param) +ixgbe_dev_interrupt_handler(__rte_unused struct rte_intr_handle *handle, + void *param) { - int64_t timeout; - struct rte_eth_link link; struct rte_eth_dev *dev = (struct rte_eth_dev *)param; - struct ixgbe_interrupt *intr = - IXGBE_DEV_PRIVATE_TO_INTR(dev->data->dev_private); - - /* get the link status before link update, for predicting later */ - memset(&link, 0, sizeof(link)); - rte_ixgbe_dev_atomic_read_link_status(dev, &link); ixgbe_dev_interrupt_get_status(dev); ixgbe_dev_interrupt_action(dev); - - if (!(intr->flags & IXGBE_FLAG_NEED_LINK_UPDATE)) - return; - - /* likely to up */ - if (!link.link_status) - /* handle it 1 sec later, wait it being stable */ - timeout = IXGBE_LINK_UP_CHECK_TIMEOUT; - /* likely to down */ - else - /* handle it 4 sec later, wait it being stable */ - timeout = IXGBE_LINK_DOWN_CHECK_TIMEOUT; - - ixgbe_dev_link_status_print(dev); - if (rte_eal_alarm_set(timeout * 1000, - ixgbe_dev_interrupt_delayed_handler, param) < 0) - PMD_INIT_LOG(ERR, "Error setting alarm"); } static int @@ -1566,6 +2180,7 @@ ixgbe_flow_ctrl_set(struct rte_eth_dev *dev, struct rte_eth_fc_conf *fc_conf) int err; uint32_t rx_buf_size; uint32_t max_high_water; + uint32_t mflcn; enum ixgbe_fc_mode rte_fcmode_2_ixgbe_fcmode[] = { ixgbe_fc_none, ixgbe_fc_rx_pause, @@ -1594,117 +2209,1007 @@ ixgbe_flow_ctrl_set(struct rte_eth_dev *dev, struct rte_eth_fc_conf *fc_conf) hw->fc.requested_mode = rte_fcmode_2_ixgbe_fcmode[fc_conf->mode]; hw->fc.pause_time = fc_conf->pause_time; hw->fc.high_water[0] = fc_conf->high_water; - hw->fc.low_water = fc_conf->low_water; + hw->fc.low_water[0] = fc_conf->low_water; hw->fc.send_xon = fc_conf->send_xon; - err = ixgbe_fc_enable(hw, 0); + err = ixgbe_fc_enable(hw); + /* Not negotiated is not an error case */ if ((err == IXGBE_SUCCESS) || (err == IXGBE_ERR_FC_NOT_NEGOTIATED)) { - return 0; - } - - PMD_INIT_LOG(ERR, "ixgbe_fc_enable = 0x%x \n", err); - return -EIO; -} - -static void -ixgbe_add_rar(struct rte_eth_dev *dev, struct ether_addr *mac_addr, - uint32_t index, uint32_t pool) -{ - struct ixgbe_hw *hw = IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private); - uint32_t enable_addr = 1; - ixgbe_set_rar(hw, index, mac_addr->addr_bytes, pool, enable_addr); -} + /* check if we want to forward MAC frames - driver doesn't have native + * capability to do that, so we'll write the registers ourselves */ -static void -ixgbe_remove_rar(struct rte_eth_dev *dev, uint32_t index) -{ - struct ixgbe_hw *hw = IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private); + mflcn = IXGBE_READ_REG(hw, IXGBE_MFLCN); - ixgbe_clear_rar(hw, index); -} + /* set or clear MFLCN.PMCF bit depending on configuration */ + if (fc_conf->mac_ctrl_frame_fwd != 0) + mflcn |= IXGBE_MFLCN_PMCF; + else + mflcn &= ~IXGBE_MFLCN_PMCF; -/* - * Virtual Function operations - */ -static void -ixgbevf_intr_disable(struct ixgbe_hw *hw) -{ - PMD_INIT_LOG(DEBUG, "ixgbevf_intr_disable"); + IXGBE_WRITE_REG(hw, IXGBE_MFLCN, mflcn); + IXGBE_WRITE_FLUSH(hw); - /* Clear interrupt mask to stop from interrupts being generated */ - IXGBE_WRITE_REG(hw, IXGBE_VTEIMC, IXGBE_VF_IRQ_CLEAR_MASK); + return 0; + } - IXGBE_WRITE_FLUSH(hw); + PMD_INIT_LOG(ERR, "ixgbe_fc_enable = 0x%x \n", err); + return -EIO; } +/** + * ixgbe_pfc_enable_generic - Enable flow control + * @hw: pointer to hardware structure + * @tc_num: traffic class number + * Enable flow control according to the current settings. + */ static int -ixgbevf_dev_configure(struct rte_eth_dev *dev, uint16_t nb_rx_q, uint16_t nb_tx_q) +ixgbe_dcb_pfc_enable_generic(struct ixgbe_hw *hw,uint8_t tc_num) { - int diag; - struct rte_eth_conf* conf = &dev->data->dev_conf; + int ret_val = 0; + uint32_t mflcn_reg, fccfg_reg; + uint32_t reg; + uint32_t fcrtl, fcrth; + uint8_t i; + uint8_t nb_rx_en; + + /* Validate the water mark configuration */ + if (!hw->fc.pause_time) { + ret_val = IXGBE_ERR_INVALID_LINK_SETTINGS; + goto out; + } - PMD_INIT_FUNC_TRACE(); + /* Low water mark of zero causes XOFF floods */ + if (hw->fc.current_mode & ixgbe_fc_tx_pause) { + /* High/Low water can not be 0 */ + if( (!hw->fc.high_water[tc_num])|| (!hw->fc.low_water[tc_num])) { + PMD_INIT_LOG(ERR,"Invalid water mark configuration\n"); + ret_val = IXGBE_ERR_INVALID_LINK_SETTINGS; + goto out; + } - /* Allocate the array of pointers to RX queue structures */ - diag = ixgbe_dev_rx_queue_alloc(dev, nb_rx_q); - if (diag != 0) { - PMD_INIT_LOG(ERR, "ethdev port_id=%d allocation of array of %d" - "pointers to RX queues failed", dev->data->port_id, - nb_rx_q); - return diag; + if(hw->fc.low_water[tc_num] >= hw->fc.high_water[tc_num]) { + PMD_INIT_LOG(ERR,"Invalid water mark configuration\n"); + ret_val = IXGBE_ERR_INVALID_LINK_SETTINGS; + goto out; + } } + /* Negotiate the fc mode to use */ + ixgbe_fc_autoneg(hw); - /* Allocate the array of pointers to TX queue structures */ - diag = ixgbe_dev_tx_queue_alloc(dev, nb_tx_q); - if (diag != 0) { - PMD_INIT_LOG(ERR, "ethdev port_id=%d allocation of array of %d" - "pointers to TX queues failed", dev->data->port_id, - nb_tx_q); - return diag; + /* Disable any previous flow control settings */ + mflcn_reg = IXGBE_READ_REG(hw, IXGBE_MFLCN); + mflcn_reg &= ~(IXGBE_MFLCN_RPFCE_SHIFT | IXGBE_MFLCN_RFCE|IXGBE_MFLCN_RPFCE); + + fccfg_reg = IXGBE_READ_REG(hw, IXGBE_FCCFG); + fccfg_reg &= ~(IXGBE_FCCFG_TFCE_802_3X | IXGBE_FCCFG_TFCE_PRIORITY); + + switch (hw->fc.current_mode) { + case ixgbe_fc_none: + /* + * If the count of enabled RX Priority Flow control >1, + * and the TX pause can not be disabled + */ + nb_rx_en = 0; + for (i =0; i < IXGBE_DCB_MAX_TRAFFIC_CLASS; i++) { + reg = IXGBE_READ_REG(hw, IXGBE_FCRTH_82599(i)); + if (reg & IXGBE_FCRTH_FCEN) + nb_rx_en++; + } + if (nb_rx_en > 1) + fccfg_reg |=IXGBE_FCCFG_TFCE_PRIORITY; + break; + case ixgbe_fc_rx_pause: + /* + * Rx Flow control is enabled and Tx Flow control is + * disabled by software override. Since there really + * isn't a way to advertise that we are capable of RX + * Pause ONLY, we will advertise that we support both + * symmetric and asymmetric Rx PAUSE. Later, we will + * disable the adapter's ability to send PAUSE frames. + */ + mflcn_reg |= IXGBE_MFLCN_RPFCE; + /* + * If the count of enabled RX Priority Flow control >1, + * and the TX pause can not be disabled + */ + nb_rx_en = 0; + for (i =0; i < IXGBE_DCB_MAX_TRAFFIC_CLASS; i++) { + reg = IXGBE_READ_REG(hw, IXGBE_FCRTH_82599(i)); + if (reg & IXGBE_FCRTH_FCEN) + nb_rx_en++; + } + if (nb_rx_en > 1) + fccfg_reg |=IXGBE_FCCFG_TFCE_PRIORITY; + break; + case ixgbe_fc_tx_pause: + /* + * Tx Flow control is enabled, and Rx Flow control is + * disabled by software override. + */ + fccfg_reg |=IXGBE_FCCFG_TFCE_PRIORITY; + break; + case ixgbe_fc_full: + /* Flow control (both Rx and Tx) is enabled by SW override. */ + mflcn_reg |= IXGBE_MFLCN_RPFCE; + fccfg_reg |= IXGBE_FCCFG_TFCE_PRIORITY; + break; + default: + DEBUGOUT("Flow control param set incorrectly\n"); + ret_val = IXGBE_ERR_CONFIG; + goto out; + break; } - if (!conf->rxmode.hw_strip_crc) { + /* Set 802.3x based flow control settings. */ + mflcn_reg |= IXGBE_MFLCN_DPF; + IXGBE_WRITE_REG(hw, IXGBE_MFLCN, mflcn_reg); + IXGBE_WRITE_REG(hw, IXGBE_FCCFG, fccfg_reg); + + /* Set up and enable Rx high/low water mark thresholds, enable XON. */ + if ((hw->fc.current_mode & ixgbe_fc_tx_pause) && + hw->fc.high_water[tc_num]) { + fcrtl = (hw->fc.low_water[tc_num] << 10) | IXGBE_FCRTL_XONE; + IXGBE_WRITE_REG(hw, IXGBE_FCRTL_82599(tc_num), fcrtl); + fcrth = (hw->fc.high_water[tc_num] << 10) | IXGBE_FCRTH_FCEN; + } else { + IXGBE_WRITE_REG(hw, IXGBE_FCRTL_82599(tc_num), 0); /* - * VF has no ability to enable/disable HW CRC - * Keep the persistent behavior the same as Host PF + * In order to prevent Tx hangs when the internal Tx + * switch is enabled we must set the high water mark + * to the maximum FCRTH value. This allows the Tx + * switch to function even under heavy Rx workloads. */ - PMD_INIT_LOG(INFO, "VF can't disable HW CRC Strip\n"); - conf->rxmode.hw_strip_crc = 1; + fcrth = IXGBE_READ_REG(hw, IXGBE_RXPBSIZE(tc_num)) - 32; } + IXGBE_WRITE_REG(hw, IXGBE_FCRTH_82599(tc_num), fcrth); - return 0; + /* Configure pause time (2 TCs per register) */ + reg = hw->fc.pause_time * 0x00010001; + for (i = 0; i < (IXGBE_DCB_MAX_TRAFFIC_CLASS / 2); i++) + IXGBE_WRITE_REG(hw, IXGBE_FCTTV(i), reg); + + /* Configure flow control refresh threshold value */ + IXGBE_WRITE_REG(hw, IXGBE_FCRTV, hw->fc.pause_time / 2); + +out: + return ret_val; } static int -ixgbevf_dev_start(struct rte_eth_dev *dev) +ixgbe_dcb_pfc_enable(struct rte_eth_dev *dev,uint8_t tc_num) { - int err = 0; - PMD_INIT_LOG(DEBUG, "ixgbevf_dev_start"); + struct ixgbe_hw *hw = IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private); + int32_t ret_val = IXGBE_NOT_IMPLEMENTED; - ixgbevf_dev_tx_init(dev); - err = ixgbevf_dev_rx_init(dev); - if(err){ - ixgbe_dev_clear_queues(dev); - PMD_INIT_LOG(ERR,"Unable to initialize RX hardware\n"); - return err; + if(hw->mac.type != ixgbe_mac_82598EB) { + ret_val = ixgbe_dcb_pfc_enable_generic(hw,tc_num); } - ixgbevf_dev_rxtx_start(dev); - - return 0; + return ret_val; } -static void -ixgbevf_dev_stop(struct rte_eth_dev *dev) +static int +ixgbe_priority_flow_ctrl_set(struct rte_eth_dev *dev, struct rte_eth_pfc_conf *pfc_conf) { - struct ixgbe_hw *hw = IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private); + int err; + uint32_t rx_buf_size; + uint32_t max_high_water; + uint8_t tc_num; + uint8_t map[IXGBE_DCB_MAX_USER_PRIORITY] = { 0 }; + struct ixgbe_hw *hw = + IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private); + struct ixgbe_dcb_config *dcb_config = + IXGBE_DEV_PRIVATE_TO_DCB_CFG(dev->data->dev_private); + + enum ixgbe_fc_mode rte_fcmode_2_ixgbe_fcmode[] = { + ixgbe_fc_none, + ixgbe_fc_rx_pause, + ixgbe_fc_tx_pause, + ixgbe_fc_full + }; + + PMD_INIT_FUNC_TRACE(); + + ixgbe_dcb_unpack_map_cee(dcb_config, IXGBE_DCB_RX_CONFIG, map); + tc_num = map[pfc_conf->priority]; + rx_buf_size = IXGBE_READ_REG(hw, IXGBE_RXPBSIZE(tc_num)); + PMD_INIT_LOG(DEBUG, "Rx packet buffer size = 0x%x \n", rx_buf_size); + /* + * At least reserve one Ethernet frame for watermark + * high_water/low_water in kilo bytes for ixgbe + */ + max_high_water = (rx_buf_size - ETHER_MAX_LEN) >> IXGBE_RXPBSIZE_SHIFT; + if ((pfc_conf->fc.high_water > max_high_water) || + (pfc_conf->fc.high_water <= pfc_conf->fc.low_water)) { + PMD_INIT_LOG(ERR, "Invalid high/low water setup value in KB\n"); + PMD_INIT_LOG(ERR, "High_water must <= 0x%x\n", max_high_water); + return (-EINVAL); + } + + hw->fc.requested_mode = rte_fcmode_2_ixgbe_fcmode[pfc_conf->fc.mode]; + hw->fc.pause_time = pfc_conf->fc.pause_time; + hw->fc.send_xon = pfc_conf->fc.send_xon; + hw->fc.low_water[tc_num] = pfc_conf->fc.low_water; + hw->fc.high_water[tc_num] = pfc_conf->fc.high_water; + + err = ixgbe_dcb_pfc_enable(dev,tc_num); + + /* Not negotiated is not an error case */ + if ((err == IXGBE_SUCCESS) || (err == IXGBE_ERR_FC_NOT_NEGOTIATED)) + return 0; + + PMD_INIT_LOG(ERR, "ixgbe_dcb_pfc_enable = 0x%x \n", err); + return -EIO; +} + +static int +ixgbe_dev_rss_reta_update(struct rte_eth_dev *dev, + struct rte_eth_rss_reta *reta_conf) +{ + uint8_t i,j,mask; + uint32_t reta; + struct ixgbe_hw *hw = + IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private); + + PMD_INIT_FUNC_TRACE(); + /* + * Update Redirection Table RETA[n],n=0...31,The redirection table has + * 128-entries in 32 registers + */ + for(i = 0; i < ETH_RSS_RETA_NUM_ENTRIES; i += 4) { + if (i < ETH_RSS_RETA_NUM_ENTRIES/2) + mask = (uint8_t)((reta_conf->mask_lo >> i) & 0xF); + else + mask = (uint8_t)((reta_conf->mask_hi >> + (i - ETH_RSS_RETA_NUM_ENTRIES/2)) & 0xF); + if (mask != 0) { + reta = 0; + if (mask != 0xF) + reta = IXGBE_READ_REG(hw,IXGBE_RETA(i >> 2)); + + for (j = 0; j < 4; j++) { + if (mask & (0x1 << j)) { + if (mask != 0xF) + reta &= ~(0xFF << 8 * j); + reta |= reta_conf->reta[i + j] << 8*j; + } + } + IXGBE_WRITE_REG(hw, IXGBE_RETA(i >> 2),reta); + } + } + + return 0; +} + +static int +ixgbe_dev_rss_reta_query(struct rte_eth_dev *dev, + struct rte_eth_rss_reta *reta_conf) +{ + uint8_t i,j,mask; + uint32_t reta; + struct ixgbe_hw *hw = + IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private); + + PMD_INIT_FUNC_TRACE(); + /* + * Read Redirection Table RETA[n],n=0...31,The redirection table has + * 128-entries in 32 registers + */ + for(i = 0; i < ETH_RSS_RETA_NUM_ENTRIES; i += 4) { + if (i < ETH_RSS_RETA_NUM_ENTRIES/2) + mask = (uint8_t)((reta_conf->mask_lo >> i) & 0xF); + else + mask = (uint8_t)((reta_conf->mask_hi >> + (i - ETH_RSS_RETA_NUM_ENTRIES/2)) & 0xF); + + if (mask != 0) { + reta = IXGBE_READ_REG(hw,IXGBE_RETA(i >> 2)); + for (j = 0; j < 4; j++) { + if (mask & (0x1 << j)) + reta_conf->reta[i + j] = + (uint8_t)((reta >> 8 * j) & 0xFF); + } + } + } + + return 0; +} + +static void +ixgbe_add_rar(struct rte_eth_dev *dev, struct ether_addr *mac_addr, + uint32_t index, uint32_t pool) +{ + struct ixgbe_hw *hw = IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private); + uint32_t enable_addr = 1; + + ixgbe_set_rar(hw, index, mac_addr->addr_bytes, pool, enable_addr); +} + +static void +ixgbe_remove_rar(struct rte_eth_dev *dev, uint32_t index) +{ + struct ixgbe_hw *hw = IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private); + + ixgbe_clear_rar(hw, index); +} + +/* + * Virtual Function operations + */ +static void +ixgbevf_intr_disable(struct ixgbe_hw *hw) +{ + PMD_INIT_LOG(DEBUG, "ixgbevf_intr_disable"); + + /* Clear interrupt mask to stop from interrupts being generated */ + IXGBE_WRITE_REG(hw, IXGBE_VTEIMC, IXGBE_VF_IRQ_CLEAR_MASK); + + IXGBE_WRITE_FLUSH(hw); +} + +static int +ixgbevf_dev_configure(struct rte_eth_dev *dev) +{ + struct rte_eth_conf* conf = &dev->data->dev_conf; + + PMD_INIT_LOG(DEBUG, "\nConfigured Virtual Function port id: %d\n", + dev->data->port_id); + + /* + * VF has no ability to enable/disable HW CRC + * Keep the persistent behavior the same as Host PF + */ +#ifndef RTE_LIBRTE_IXGBE_PF_DISABLE_STRIP_CRC + if (!conf->rxmode.hw_strip_crc) { + PMD_INIT_LOG(INFO, "VF can't disable HW CRC Strip\n"); + conf->rxmode.hw_strip_crc = 1; + } +#else + if (conf->rxmode.hw_strip_crc) { + PMD_INIT_LOG(INFO, "VF can't enable HW CRC Strip\n"); + conf->rxmode.hw_strip_crc = 0; + } +#endif + + return 0; +} + +static int +ixgbevf_dev_start(struct rte_eth_dev *dev) +{ + struct ixgbe_hw *hw = + IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private); + int err, mask = 0; + + PMD_INIT_LOG(DEBUG, "ixgbevf_dev_start"); + + hw->mac.ops.reset_hw(hw); + + /* negotiate mailbox API version to use with the PF. */ + ixgbevf_negotiate_api(hw); + + ixgbevf_dev_tx_init(dev); + + /* This can fail when allocating mbufs for descriptor rings */ + err = ixgbevf_dev_rx_init(dev); + if (err) { + PMD_INIT_LOG(ERR, "Unable to initialize RX hardware (%d)\n", err); + ixgbe_dev_clear_queues(dev); + return err; + } + + /* Set vfta */ + ixgbevf_set_vfta_all(dev,1); + + /* Set HW strip */ + mask = ETH_VLAN_STRIP_MASK | ETH_VLAN_FILTER_MASK | \ + ETH_VLAN_EXTEND_MASK; + ixgbevf_vlan_offload_set(dev, mask); + + ixgbevf_dev_rxtx_start(dev); + + return 0; +} + +static void +ixgbevf_dev_stop(struct rte_eth_dev *dev) +{ + struct ixgbe_hw *hw = IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private); PMD_INIT_LOG(DEBUG, "ixgbevf_dev_stop"); - ixgbe_reset_hw(hw); - hw->adapter_stopped = 0; + hw->adapter_stopped = TRUE; ixgbe_stop_adapter(hw); + + /* + * Clear what we set, but we still keep shadow_vfta to + * restore after device starts + */ + ixgbevf_set_vfta_all(dev,0); + + ixgbe_dev_clear_queues(dev); +} + +static void +ixgbevf_dev_close(struct rte_eth_dev *dev) +{ + struct ixgbe_hw *hw = IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private); + + PMD_INIT_LOG(DEBUG, "ixgbevf_dev_close"); + + ixgbe_reset_hw(hw); + + ixgbevf_dev_stop(dev); + /* reprogram the RAR[0] in case user changed it. */ ixgbe_set_rar(hw, 0, hw->mac.addr, 0, IXGBE_RAH_AV); } + +static void ixgbevf_set_vfta_all(struct rte_eth_dev *dev, bool on) +{ + struct ixgbe_hw *hw = IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private); + struct ixgbe_vfta * shadow_vfta = + IXGBE_DEV_PRIVATE_TO_VFTA(dev->data->dev_private); + int i = 0, j = 0, vfta = 0, mask = 1; + + for (i = 0; i < IXGBE_VFTA_SIZE; i++){ + vfta = shadow_vfta->vfta[i]; + if(vfta){ + mask = 1; + for (j = 0; j < 32; j++){ + if(vfta & mask) + ixgbe_set_vfta(hw, (i<<5)+j, 0, on); + mask<<=1; + } + } + } + +} + +static int +ixgbevf_vlan_filter_set(struct rte_eth_dev *dev, uint16_t vlan_id, int on) +{ + struct ixgbe_hw *hw = + IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private); + struct ixgbe_vfta * shadow_vfta = + IXGBE_DEV_PRIVATE_TO_VFTA(dev->data->dev_private); + uint32_t vid_idx = 0; + uint32_t vid_bit = 0; + int ret = 0; + + PMD_INIT_FUNC_TRACE(); + + /* vind is not used in VF driver, set to 0, check ixgbe_set_vfta_vf */ + ret = ixgbe_set_vfta(hw, vlan_id, 0, !!on); + if(ret){ + PMD_INIT_LOG(ERR, "Unable to set VF vlan"); + return ret; + } + vid_idx = (uint32_t) ((vlan_id >> 5) & 0x7F); + vid_bit = (uint32_t) (1 << (vlan_id & 0x1F)); + + /* Save what we set and retore it after device reset */ + if (on) + shadow_vfta->vfta[vid_idx] |= vid_bit; + else + shadow_vfta->vfta[vid_idx] &= ~vid_bit; + + return 0; +} + +static void +ixgbevf_vlan_strip_queue_set(struct rte_eth_dev *dev, uint16_t queue, int on) +{ + struct ixgbe_hw *hw = + IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private); + uint32_t ctrl; + + PMD_INIT_FUNC_TRACE(); + + if(queue >= hw->mac.max_rx_queues) + return; + + ctrl = IXGBE_READ_REG(hw, IXGBE_RXDCTL(queue)); + if(on) + ctrl |= IXGBE_RXDCTL_VME; + else + ctrl &= ~IXGBE_RXDCTL_VME; + IXGBE_WRITE_REG(hw, IXGBE_RXDCTL(queue), ctrl); + + ixgbe_vlan_hw_strip_bitmap_set( dev, queue, on); +} + +static void +ixgbevf_vlan_offload_set(struct rte_eth_dev *dev, int mask) +{ + struct ixgbe_hw *hw = + IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private); + uint16_t i; + int on = 0; + + /* VF function only support hw strip feature, others are not support */ + if(mask & ETH_VLAN_STRIP_MASK){ + on = !!(dev->data->dev_conf.rxmode.hw_vlan_strip); + + for(i=0; i < hw->mac.max_rx_queues; i++) + ixgbevf_vlan_strip_queue_set(dev,i,on); + } +} + +static int +ixgbe_vmdq_mode_check(struct ixgbe_hw *hw) +{ + uint32_t reg_val; + + /* we only need to do this if VMDq is enabled */ + reg_val = IXGBE_READ_REG(hw, IXGBE_VT_CTL); + if (!(reg_val & IXGBE_VT_CTL_VT_ENABLE)) { + PMD_INIT_LOG(ERR, "VMDq must be enabled for this setting\n"); + return (-1); + } + + return 0; +} + +static uint32_t +ixgbe_uta_vector(struct ixgbe_hw *hw, struct ether_addr* uc_addr) +{ + uint32_t vector = 0; + switch (hw->mac.mc_filter_type) { + case 0: /* use bits [47:36] of the address */ + vector = ((uc_addr->addr_bytes[4] >> 4) | + (((uint16_t)uc_addr->addr_bytes[5]) << 4)); + break; + case 1: /* use bits [46:35] of the address */ + vector = ((uc_addr->addr_bytes[4] >> 3) | + (((uint16_t)uc_addr->addr_bytes[5]) << 5)); + break; + case 2: /* use bits [45:34] of the address */ + vector = ((uc_addr->addr_bytes[4] >> 2) | + (((uint16_t)uc_addr->addr_bytes[5]) << 6)); + break; + case 3: /* use bits [43:32] of the address */ + vector = ((uc_addr->addr_bytes[4]) | + (((uint16_t)uc_addr->addr_bytes[5]) << 8)); + break; + default: /* Invalid mc_filter_type */ + break; + } + + /* vector can only be 12-bits or boundary will be exceeded */ + vector &= 0xFFF; + return vector; +} + +static int +ixgbe_uc_hash_table_set(struct rte_eth_dev *dev,struct ether_addr* mac_addr, + uint8_t on) +{ + uint32_t vector; + uint32_t uta_idx; + uint32_t reg_val; + uint32_t uta_shift; + uint32_t rc; + const uint32_t ixgbe_uta_idx_mask = 0x7F; + const uint32_t ixgbe_uta_bit_shift = 5; + const uint32_t ixgbe_uta_bit_mask = (0x1 << ixgbe_uta_bit_shift) - 1; + const uint32_t bit1 = 0x1; + + struct ixgbe_hw *hw = + IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private); + struct ixgbe_uta_info *uta_info = + IXGBE_DEV_PRIVATE_TO_UTA(dev->data->dev_private); + + /* The UTA table only exists on 82599 hardware and newer */ + if (hw->mac.type < ixgbe_mac_82599EB) + return (-ENOTSUP); + + vector = ixgbe_uta_vector(hw,mac_addr); + uta_idx = (vector >> ixgbe_uta_bit_shift) & ixgbe_uta_idx_mask; + uta_shift = vector & ixgbe_uta_bit_mask; + + rc = ((uta_info->uta_shadow[uta_idx] >> uta_shift & bit1) != 0); + if(rc == on) + return 0; + + reg_val = IXGBE_READ_REG(hw, IXGBE_UTA(uta_idx)); + if (on) { + uta_info->uta_in_use++; + reg_val |= (bit1 << uta_shift); + uta_info->uta_shadow[uta_idx] |= (bit1 << uta_shift); + } else { + uta_info->uta_in_use--; + reg_val &= ~(bit1 << uta_shift); + uta_info->uta_shadow[uta_idx] &= ~(bit1 << uta_shift); + } + + IXGBE_WRITE_REG(hw, IXGBE_UTA(uta_idx), reg_val); + + if (uta_info->uta_in_use > 0) + IXGBE_WRITE_REG(hw, IXGBE_MCSTCTRL, + IXGBE_MCSTCTRL_MFE | hw->mac.mc_filter_type); + else + IXGBE_WRITE_REG(hw, IXGBE_MCSTCTRL,hw->mac.mc_filter_type); + + return 0; +} + +static int +ixgbe_uc_all_hash_table_set(struct rte_eth_dev *dev, uint8_t on) +{ + int i; + struct ixgbe_hw *hw = + IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private); + struct ixgbe_uta_info *uta_info = + IXGBE_DEV_PRIVATE_TO_UTA(dev->data->dev_private); + + /* The UTA table only exists on 82599 hardware and newer */ + if (hw->mac.type < ixgbe_mac_82599EB) + return (-ENOTSUP); + + if(on) { + for (i = 0; i < ETH_VMDQ_NUM_UC_HASH_ARRAY; i++) { + uta_info->uta_shadow[i] = ~0; + IXGBE_WRITE_REG(hw, IXGBE_UTA(i), ~0); + } + } else { + for (i = 0; i < ETH_VMDQ_NUM_UC_HASH_ARRAY; i++) { + uta_info->uta_shadow[i] = 0; + IXGBE_WRITE_REG(hw, IXGBE_UTA(i), 0); + } + } + return 0; + +} +static int +ixgbe_set_pool_rx_mode(struct rte_eth_dev *dev, uint16_t pool, + uint16_t rx_mask, uint8_t on) +{ + int val = 0; + + struct ixgbe_hw *hw = + IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private); + uint32_t vmolr = IXGBE_READ_REG(hw, IXGBE_VMOLR(pool)); + + if (hw->mac.type == ixgbe_mac_82598EB) { + PMD_INIT_LOG(ERR, "setting VF receive mode set should be done" + " on 82599 hardware and newer\n"); + return (-ENOTSUP); + } + if (ixgbe_vmdq_mode_check(hw) < 0) + return (-ENOTSUP); + + if (rx_mask & ETH_VMDQ_ACCEPT_UNTAG ) + val |= IXGBE_VMOLR_AUPE; + if (rx_mask & ETH_VMDQ_ACCEPT_HASH_MC ) + val |= IXGBE_VMOLR_ROMPE; + if (rx_mask & ETH_VMDQ_ACCEPT_HASH_UC) + val |= IXGBE_VMOLR_ROPE; + if (rx_mask & ETH_VMDQ_ACCEPT_BROADCAST) + val |= IXGBE_VMOLR_BAM; + if (rx_mask & ETH_VMDQ_ACCEPT_MULTICAST) + val |= IXGBE_VMOLR_MPE; + + if (on) + vmolr |= val; + else + vmolr &= ~val; + + IXGBE_WRITE_REG(hw, IXGBE_VMOLR(pool), vmolr); + + return 0; +} + +static int +ixgbe_set_pool_rx(struct rte_eth_dev *dev, uint16_t pool, uint8_t on) +{ + uint32_t reg,addr; + uint32_t val; + const uint8_t bit1 = 0x1; + + struct ixgbe_hw *hw = + IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private); + + if (ixgbe_vmdq_mode_check(hw) < 0) + return (-ENOTSUP); + + addr = IXGBE_VFRE(pool >= ETH_64_POOLS/2); + reg = IXGBE_READ_REG(hw, addr); + val = bit1 << pool; + + if (on) + reg |= val; + else + reg &= ~val; + + IXGBE_WRITE_REG(hw, addr,reg); + + return 0; +} + +static int +ixgbe_set_pool_tx(struct rte_eth_dev *dev, uint16_t pool, uint8_t on) +{ + uint32_t reg,addr; + uint32_t val; + const uint8_t bit1 = 0x1; + + struct ixgbe_hw *hw = + IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private); + + if (ixgbe_vmdq_mode_check(hw) < 0) + return (-ENOTSUP); + + addr = IXGBE_VFTE(pool >= ETH_64_POOLS/2); + reg = IXGBE_READ_REG(hw, addr); + val = bit1 << pool; + + if (on) + reg |= val; + else + reg &= ~val; + + IXGBE_WRITE_REG(hw, addr,reg); + + return 0; +} + +static int +ixgbe_set_pool_vlan_filter(struct rte_eth_dev *dev, uint16_t vlan, + uint64_t pool_mask, uint8_t vlan_on) +{ + int ret = 0; + uint16_t pool_idx; + struct ixgbe_hw *hw = + IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private); + + 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))) + ret = hw->mac.ops.set_vfta(hw,vlan,pool_idx,vlan_on); + if (ret < 0) + return ret; + } + + return ret; +} + +static int +ixgbe_mirror_rule_set(struct rte_eth_dev *dev, + struct rte_eth_vmdq_mirror_conf *mirror_conf, + uint8_t rule_id, uint8_t on) +{ + uint32_t mr_ctl,vlvf; + uint32_t mp_lsb = 0; + uint32_t mv_msb = 0; + uint32_t mv_lsb = 0; + uint32_t mp_msb = 0; + uint8_t i = 0; + int reg_index = 0; + uint64_t vlan_mask = 0; + + const uint8_t pool_mask_offset = 32; + const uint8_t vlan_mask_offset = 32; + const uint8_t dst_pool_offset = 8; + const uint8_t rule_mr_offset = 4; + const uint8_t mirror_rule_mask= 0x0F; + + struct ixgbe_mirror_info *mr_info = + (IXGBE_DEV_PRIVATE_TO_PFDATA(dev->data->dev_private)); + struct ixgbe_hw *hw = + IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private); + + if (ixgbe_vmdq_mode_check(hw) < 0) + return (-ENOTSUP); + + /* Check if vlan mask is valid */ + if ((mirror_conf->rule_type_mask & ETH_VMDQ_VLAN_MIRROR) && (on)) { + if (mirror_conf->vlan.vlan_mask == 0) + return (-EINVAL); + } + + /* Check if vlan id is valid and find conresponding VLAN ID index in VLVF */ + if (mirror_conf->rule_type_mask & ETH_VMDQ_VLAN_MIRROR) { + for (i = 0;i < IXGBE_VLVF_ENTRIES; i++) { + if (mirror_conf->vlan.vlan_mask & (1ULL << i)) { + /* search vlan id related pool vlan filter index */ + reg_index = ixgbe_find_vlvf_slot(hw, + mirror_conf->vlan.vlan_id[i]); + if(reg_index < 0) + return (-EINVAL); + vlvf = IXGBE_READ_REG(hw, IXGBE_VLVF(reg_index)); + if ((vlvf & IXGBE_VLVF_VIEN) && + ((vlvf & IXGBE_VLVF_VLANID_MASK) + == mirror_conf->vlan.vlan_id[i])) + vlan_mask |= (1ULL << reg_index); + else + return (-EINVAL); + } + } + + if (on) { + mv_lsb = vlan_mask & 0xFFFFFFFF; + mv_msb = vlan_mask >> vlan_mask_offset; + + mr_info->mr_conf[rule_id].vlan.vlan_mask = + mirror_conf->vlan.vlan_mask; + for(i = 0 ;i < ETH_VMDQ_MAX_VLAN_FILTERS; i++) { + if(mirror_conf->vlan.vlan_mask & (1ULL << i)) + mr_info->mr_conf[rule_id].vlan.vlan_id[i] = + mirror_conf->vlan.vlan_id[i]; + } + } else { + mv_lsb = 0; + mv_msb = 0; + mr_info->mr_conf[rule_id].vlan.vlan_mask = 0; + for(i = 0 ;i < ETH_VMDQ_MAX_VLAN_FILTERS; i++) + mr_info->mr_conf[rule_id].vlan.vlan_id[i] = 0; + } + } + + /* + * if enable pool mirror, write related pool mask register,if disable + * pool mirror, clear PFMRVM register + */ + if (mirror_conf->rule_type_mask & ETH_VMDQ_POOL_MIRROR) { + if (on) { + mp_lsb = mirror_conf->pool_mask & 0xFFFFFFFF; + mp_msb = mirror_conf->pool_mask >> pool_mask_offset; + mr_info->mr_conf[rule_id].pool_mask = + mirror_conf->pool_mask; + + } else { + mp_lsb = 0; + mp_msb = 0; + mr_info->mr_conf[rule_id].pool_mask = 0; + } + } + + /* read mirror control register and recalculate it */ + mr_ctl = IXGBE_READ_REG(hw,IXGBE_MRCTL(rule_id)); + + if (on) { + mr_ctl |= mirror_conf->rule_type_mask; + mr_ctl &= mirror_rule_mask; + mr_ctl |= mirror_conf->dst_pool << dst_pool_offset; + } else + mr_ctl &= ~(mirror_conf->rule_type_mask & mirror_rule_mask); + + mr_info->mr_conf[rule_id].rule_type_mask = (uint8_t)(mr_ctl & mirror_rule_mask); + mr_info->mr_conf[rule_id].dst_pool = mirror_conf->dst_pool; + + /* write mirrror control register */ + IXGBE_WRITE_REG(hw, IXGBE_MRCTL(rule_id), mr_ctl); + + /* write pool mirrror control register */ + if (mirror_conf->rule_type_mask & ETH_VMDQ_POOL_MIRROR) { + IXGBE_WRITE_REG(hw, IXGBE_VMRVM(rule_id), mp_lsb); + IXGBE_WRITE_REG(hw, IXGBE_VMRVM(rule_id + rule_mr_offset), + mp_msb); + } + /* write VLAN mirrror control register */ + if (mirror_conf->rule_type_mask & ETH_VMDQ_VLAN_MIRROR) { + IXGBE_WRITE_REG(hw, IXGBE_VMRVLAN(rule_id), mv_lsb); + IXGBE_WRITE_REG(hw, IXGBE_VMRVLAN(rule_id + rule_mr_offset), + mv_msb); + } + + return 0; +} + +static int +ixgbe_mirror_rule_reset(struct rte_eth_dev *dev, uint8_t rule_id) +{ + int mr_ctl = 0; + uint32_t lsb_val = 0; + uint32_t msb_val = 0; + const uint8_t rule_mr_offset = 4; + + struct ixgbe_hw *hw = + IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private); + struct ixgbe_mirror_info *mr_info = + (IXGBE_DEV_PRIVATE_TO_PFDATA(dev->data->dev_private)); + + if (ixgbe_vmdq_mode_check(hw) < 0) + return (-ENOTSUP); + + memset(&mr_info->mr_conf[rule_id], 0, + sizeof(struct rte_eth_vmdq_mirror_conf)); + + /* clear PFVMCTL register */ + IXGBE_WRITE_REG(hw, IXGBE_MRCTL(rule_id), mr_ctl); + + /* clear pool mask register */ + IXGBE_WRITE_REG(hw, IXGBE_VMRVM(rule_id), lsb_val); + IXGBE_WRITE_REG(hw, IXGBE_VMRVM(rule_id + rule_mr_offset), msb_val); + + /* clear vlan mask register */ + IXGBE_WRITE_REG(hw, IXGBE_VMRVLAN(rule_id), lsb_val); + IXGBE_WRITE_REG(hw, IXGBE_VMRVLAN(rule_id + rule_mr_offset), msb_val); + + return 0; +} + +static void +ixgbevf_add_mac_addr(struct rte_eth_dev *dev, struct ether_addr *mac_addr, + __attribute__((unused)) uint32_t index, + __attribute__((unused)) uint32_t pool) +{ + struct ixgbe_hw *hw = IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private); + int diag; + + /* + * On a 82599 VF, adding again the same MAC addr is not an idempotent + * operation. Trap this case to avoid exhausting the [very limited] + * set of PF resources used to store VF MAC addresses. + */ + if (memcmp(hw->mac.perm_addr, mac_addr, sizeof(struct ether_addr)) == 0) + return; + diag = ixgbevf_set_uc_addr_vf(hw, 2, mac_addr->addr_bytes); + if (diag == 0) + return; + PMD_DRV_LOG(ERR, "Unable to add MAC address - diag=%d", diag); +} + +static void +ixgbevf_remove_mac_addr(struct rte_eth_dev *dev, uint32_t index) +{ + struct ixgbe_hw *hw = IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private); + struct ether_addr *perm_addr = (struct ether_addr *) hw->mac.perm_addr; + struct ether_addr *mac_addr; + uint32_t i; + int diag; + + /* + * The IXGBE_VF_SET_MACVLAN command of the ixgbe-pf driver does + * not support the deletion of a given MAC address. + * Instead, it imposes to delete all MAC addresses, then to add again + * all MAC addresses with the exception of the one to be deleted. + */ + (void) ixgbevf_set_uc_addr_vf(hw, 0, NULL); + + /* + * Add again all MAC addresses, with the exception of the deleted one + * and of the permanent MAC address. + */ + for (i = 0, mac_addr = dev->data->mac_addrs; + i < hw->mac.num_rar_entries; i++, mac_addr++) { + /* Skip the deleted MAC address */ + if (i == index) + continue; + /* Skip NULL MAC addresses */ + if (is_zero_ether_addr(mac_addr)) + continue; + /* Skip the permanent MAC address */ + if (memcmp(perm_addr, mac_addr, sizeof(struct ether_addr)) == 0) + continue; + diag = ixgbevf_set_uc_addr_vf(hw, 2, mac_addr->addr_bytes); + if (diag != 0) + PMD_DRV_LOG(ERR, + "Adding again MAC address " + "%02x:%02x:%02x:%02x:%02x:%02x failed " + "diag=%d", + mac_addr->addr_bytes[0], + mac_addr->addr_bytes[1], + mac_addr->addr_bytes[2], + mac_addr->addr_bytes[3], + mac_addr->addr_bytes[4], + mac_addr->addr_bytes[5], + diag); + } +} + +static struct rte_driver rte_ixgbe_driver = { + .type = PMD_PDEV, + .init = rte_ixgbe_pmd_init, +}; + +static struct rte_driver rte_ixgbevf_driver = { + .type = PMD_PDEV, + .init = rte_ixgbevf_pmd_init, +}; + +PMD_REGISTER_DRIVER(rte_ixgbe_driver); +PMD_REGISTER_DRIVER(rte_ixgbevf_driver);