X-Git-Url: http://git.droids-corp.org/?a=blobdiff_plain;f=drivers%2Fnet%2Fe1000%2Figb_ethdev.c;h=045fc6343f181902c2f83b5c6698efbd7224137c;hb=09419f235e099ecb265a590778fe64a685a2a241;hp=11e8ab8ba0dfdc103647eb787043db118508be0e;hpb=8208e85a2240f252965424253caeb8664c1a7bac;p=dpdk.git diff --git a/drivers/net/e1000/igb_ethdev.c b/drivers/net/e1000/igb_ethdev.c index 11e8ab8ba0..045fc6343f 100644 --- a/drivers/net/e1000/igb_ethdev.c +++ b/drivers/net/e1000/igb_ethdev.c @@ -1,7 +1,7 @@ /*- * BSD LICENSE * - * Copyright(c) 2010-2015 Intel Corporation. All rights reserved. + * Copyright(c) 2010-2016 Intel Corporation. All rights reserved. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -55,18 +55,20 @@ #include "e1000_logs.h" #include "base/e1000_api.h" #include "e1000_ethdev.h" +#include "igb_regs.h" /* * Default values for port configuration */ #define IGB_DEFAULT_RX_FREE_THRESH 32 -#define IGB_DEFAULT_RX_PTHRESH 8 + +#define IGB_DEFAULT_RX_PTHRESH ((hw->mac.type == e1000_i354) ? 12 : 8) #define IGB_DEFAULT_RX_HTHRESH 8 -#define IGB_DEFAULT_RX_WTHRESH 0 +#define IGB_DEFAULT_RX_WTHRESH ((hw->mac.type == e1000_82576) ? 1 : 4) -#define IGB_DEFAULT_TX_PTHRESH 32 -#define IGB_DEFAULT_TX_HTHRESH 0 -#define IGB_DEFAULT_TX_WTHRESH 0 +#define IGB_DEFAULT_TX_PTHRESH ((hw->mac.type == e1000_i354) ? 20 : 8) +#define IGB_DEFAULT_TX_HTHRESH 1 +#define IGB_DEFAULT_TX_WTHRESH ((hw->mac.type == e1000_82576) ? 1 : 16) #define IGB_HKEY_MAX_INDEX 10 @@ -76,6 +78,14 @@ #define IGB_8_BIT_WIDTH CHAR_BIT #define IGB_8_BIT_MASK UINT8_MAX +/* Additional timesync values. */ +#define E1000_CYCLECOUNTER_MASK 0xffffffffffffffffULL +#define E1000_ETQF_FILTER_1588 3 +#define IGB_82576_TSYNC_SHIFT 16 +#define E1000_INCPERIOD_82576 (1 << E1000_TIMINCA_16NS_SHIFT) +#define E1000_INCVALUE_82576 (16 << IGB_82576_TSYNC_SHIFT) +#define E1000_TSAUXC_DISABLE_SYSTIME 0x80000000 + static int eth_igb_configure(struct rte_eth_dev *dev); static int eth_igb_start(struct rte_eth_dev *dev); static void eth_igb_stop(struct rte_eth_dev *dev); @@ -88,9 +98,13 @@ static int eth_igb_link_update(struct rte_eth_dev *dev, int wait_to_complete); static void eth_igb_stats_get(struct rte_eth_dev *dev, struct rte_eth_stats *rte_stats); +static int eth_igb_xstats_get(struct rte_eth_dev *dev, + struct rte_eth_xstats *xstats, unsigned n); static void eth_igb_stats_reset(struct rte_eth_dev *dev); +static void eth_igb_xstats_reset(struct rte_eth_dev *dev); static void eth_igb_infos_get(struct rte_eth_dev *dev, struct rte_eth_dev_info *dev_info); +static const uint32_t *eth_igb_supported_ptypes_get(struct rte_eth_dev *dev); static void eth_igbvf_infos_get(struct rte_eth_dev *dev, struct rte_eth_dev_info *dev_info); static int eth_igb_flow_ctrl_get(struct rte_eth_dev *dev, @@ -98,6 +112,7 @@ static int eth_igb_flow_ctrl_get(struct rte_eth_dev *dev, static int eth_igb_flow_ctrl_set(struct rte_eth_dev *dev, struct rte_eth_fc_conf *fc_conf); static int eth_igb_lsc_interrupt_setup(struct rte_eth_dev *dev); +static int eth_igb_rxq_interrupt_setup(struct rte_eth_dev *dev); static int eth_igb_interrupt_get_status(struct rte_eth_dev *dev); static int eth_igb_interrupt_action(struct rte_eth_dev *dev); static void eth_igb_interrupt_handler(struct rte_intr_handle *handle, @@ -112,7 +127,9 @@ static int eth_igb_mtu_set(struct rte_eth_dev *dev, uint16_t mtu); static int eth_igb_vlan_filter_set(struct rte_eth_dev *dev, uint16_t vlan_id, int on); -static void eth_igb_vlan_tpid_set(struct rte_eth_dev *dev, uint16_t tpid_id); +static int eth_igb_vlan_tpid_set(struct rte_eth_dev *dev, + enum rte_vlan_type vlan_type, + uint16_t tpid_id); static void eth_igb_vlan_offload_set(struct rte_eth_dev *dev, int mask); static void igb_vlan_hw_filter_enable(struct rte_eth_dev *dev); @@ -131,19 +148,34 @@ static void eth_igb_rar_set(struct rte_eth_dev *dev, struct ether_addr *mac_addr, uint32_t index, uint32_t pool); static void eth_igb_rar_clear(struct rte_eth_dev *dev, uint32_t index); +static void eth_igb_default_mac_addr_set(struct rte_eth_dev *dev, + struct ether_addr *addr); static void igbvf_intr_disable(struct e1000_hw *hw); static int igbvf_dev_configure(struct rte_eth_dev *dev); static int igbvf_dev_start(struct rte_eth_dev *dev); static void igbvf_dev_stop(struct rte_eth_dev *dev); static void igbvf_dev_close(struct rte_eth_dev *dev); +static void igbvf_promiscuous_enable(struct rte_eth_dev *dev); +static void igbvf_promiscuous_disable(struct rte_eth_dev *dev); +static void igbvf_allmulticast_enable(struct rte_eth_dev *dev); +static void igbvf_allmulticast_disable(struct rte_eth_dev *dev); static int eth_igbvf_link_update(struct e1000_hw *hw); -static void eth_igbvf_stats_get(struct rte_eth_dev *dev, struct rte_eth_stats *rte_stats); +static void eth_igbvf_stats_get(struct rte_eth_dev *dev, + struct rte_eth_stats *rte_stats); +static int eth_igbvf_xstats_get(struct rte_eth_dev *dev, + struct rte_eth_xstats *xstats, unsigned n); static void eth_igbvf_stats_reset(struct rte_eth_dev *dev); static int igbvf_vlan_filter_set(struct rte_eth_dev *dev, uint16_t vlan_id, int on); static int igbvf_set_vfta(struct e1000_hw *hw, uint16_t vid, bool on); static void igbvf_set_vfta_all(struct rte_eth_dev *dev, bool on); +static void igbvf_default_mac_addr_set(struct rte_eth_dev *dev, + struct ether_addr *addr); +static int igbvf_get_reg_length(struct rte_eth_dev *dev); +static int igbvf_get_regs(struct rte_eth_dev *dev, + struct rte_dev_reg_info *regs); + static int eth_igb_rss_reta_update(struct rte_eth_dev *dev, struct rte_eth_rss_reta_entry64 *reta_conf, uint16_t reta_size); @@ -195,10 +227,38 @@ static int eth_igb_filter_ctrl(struct rte_eth_dev *dev, enum rte_filter_type filter_type, enum rte_filter_op filter_op, void *arg); - +static int eth_igb_get_reg_length(struct rte_eth_dev *dev); +static int eth_igb_get_regs(struct rte_eth_dev *dev, + struct rte_dev_reg_info *regs); +static int eth_igb_get_eeprom_length(struct rte_eth_dev *dev); +static int eth_igb_get_eeprom(struct rte_eth_dev *dev, + struct rte_dev_eeprom_info *eeprom); +static int eth_igb_set_eeprom(struct rte_eth_dev *dev, + struct rte_dev_eeprom_info *eeprom); static int eth_igb_set_mc_addr_list(struct rte_eth_dev *dev, struct ether_addr *mc_addr_set, uint32_t nb_mc_addr); +static int igb_timesync_enable(struct rte_eth_dev *dev); +static int igb_timesync_disable(struct rte_eth_dev *dev); +static int igb_timesync_read_rx_timestamp(struct rte_eth_dev *dev, + struct timespec *timestamp, + uint32_t flags); +static int igb_timesync_read_tx_timestamp(struct rte_eth_dev *dev, + struct timespec *timestamp); +static int igb_timesync_adjust_time(struct rte_eth_dev *dev, int64_t delta); +static int igb_timesync_read_time(struct rte_eth_dev *dev, + struct timespec *timestamp); +static int igb_timesync_write_time(struct rte_eth_dev *dev, + const struct timespec *timestamp); +static int eth_igb_rx_queue_intr_enable(struct rte_eth_dev *dev, + uint16_t queue_id); +static int eth_igb_rx_queue_intr_disable(struct rte_eth_dev *dev, + uint16_t queue_id); +static void eth_igb_assign_msix_vector(struct e1000_hw *hw, int8_t direction, + uint8_t queue, uint8_t msix_vector); +static void eth_igb_write_ivar(struct e1000_hw *hw, uint8_t msix_vector, + uint8_t index, uint8_t offset); +static void eth_igb_configure_msix_intr(struct rte_eth_dev *dev); /* * Define VF Stats MACRO for Non "cleared on read" register @@ -206,11 +266,10 @@ static int eth_igb_set_mc_addr_list(struct rte_eth_dev *dev, #define UPDATE_VF_STAT(reg, last, cur) \ { \ u32 latest = E1000_READ_REG(hw, reg); \ - cur += latest - last; \ + cur += (latest - last) & UINT_MAX; \ last = latest; \ } - #define IGB_FC_PAUSE_TIME 0x0680 #define IGB_LINK_UPDATE_CHECK_TIMEOUT 90 /* 9s */ #define IGB_LINK_UPDATE_CHECK_INTERVAL 100 /* ms */ @@ -241,6 +300,18 @@ static const struct rte_pci_id pci_id_igbvf_map[] = { {0}, }; +static const struct rte_eth_desc_lim rx_desc_lim = { + .nb_max = E1000_MAX_RING_DESC, + .nb_min = E1000_MIN_RING_DESC, + .nb_align = IGB_RXD_ALIGN, +}; + +static const struct rte_eth_desc_lim tx_desc_lim = { + .nb_max = E1000_MAX_RING_DESC, + .nb_min = E1000_MIN_RING_DESC, + .nb_align = IGB_RXD_ALIGN, +}; + static const struct eth_dev_ops eth_igb_ops = { .dev_configure = eth_igb_configure, .dev_start = eth_igb_start, @@ -252,13 +323,18 @@ static const struct eth_dev_ops eth_igb_ops = { .allmulticast_disable = eth_igb_allmulticast_disable, .link_update = eth_igb_link_update, .stats_get = eth_igb_stats_get, + .xstats_get = eth_igb_xstats_get, .stats_reset = eth_igb_stats_reset, + .xstats_reset = eth_igb_xstats_reset, .dev_infos_get = eth_igb_infos_get, + .dev_supported_ptypes_get = eth_igb_supported_ptypes_get, .mtu_set = eth_igb_mtu_set, .vlan_filter_set = eth_igb_vlan_filter_set, .vlan_tpid_set = eth_igb_vlan_tpid_set, .vlan_offload_set = eth_igb_vlan_offload_set, .rx_queue_setup = eth_igb_rx_queue_setup, + .rx_queue_intr_enable = eth_igb_rx_queue_intr_enable, + .rx_queue_intr_disable = eth_igb_rx_queue_intr_disable, .rx_queue_release = eth_igb_rx_queue_release, .rx_queue_count = eth_igb_rx_queue_count, .rx_descriptor_done = eth_igb_rx_descriptor_done, @@ -270,12 +346,27 @@ static const struct eth_dev_ops eth_igb_ops = { .flow_ctrl_set = eth_igb_flow_ctrl_set, .mac_addr_add = eth_igb_rar_set, .mac_addr_remove = eth_igb_rar_clear, + .mac_addr_set = eth_igb_default_mac_addr_set, .reta_update = eth_igb_rss_reta_update, .reta_query = eth_igb_rss_reta_query, .rss_hash_update = eth_igb_rss_hash_update, .rss_hash_conf_get = eth_igb_rss_hash_conf_get, .filter_ctrl = eth_igb_filter_ctrl, .set_mc_addr_list = eth_igb_set_mc_addr_list, + .rxq_info_get = igb_rxq_info_get, + .txq_info_get = igb_txq_info_get, + .timesync_enable = igb_timesync_enable, + .timesync_disable = igb_timesync_disable, + .timesync_read_rx_timestamp = igb_timesync_read_rx_timestamp, + .timesync_read_tx_timestamp = igb_timesync_read_tx_timestamp, + .get_reg_length = eth_igb_get_reg_length, + .get_reg = eth_igb_get_regs, + .get_eeprom_length = eth_igb_get_eeprom_length, + .get_eeprom = eth_igb_get_eeprom, + .set_eeprom = eth_igb_set_eeprom, + .timesync_adjust_time = igb_timesync_adjust_time, + .timesync_read_time = igb_timesync_read_time, + .timesync_write_time = igb_timesync_write_time, }; /* @@ -287,18 +378,111 @@ static const struct eth_dev_ops igbvf_eth_dev_ops = { .dev_start = igbvf_dev_start, .dev_stop = igbvf_dev_stop, .dev_close = igbvf_dev_close, + .promiscuous_enable = igbvf_promiscuous_enable, + .promiscuous_disable = igbvf_promiscuous_disable, + .allmulticast_enable = igbvf_allmulticast_enable, + .allmulticast_disable = igbvf_allmulticast_disable, .link_update = eth_igb_link_update, .stats_get = eth_igbvf_stats_get, + .xstats_get = eth_igbvf_xstats_get, .stats_reset = eth_igbvf_stats_reset, + .xstats_reset = eth_igbvf_stats_reset, .vlan_filter_set = igbvf_vlan_filter_set, .dev_infos_get = eth_igbvf_infos_get, + .dev_supported_ptypes_get = eth_igb_supported_ptypes_get, .rx_queue_setup = eth_igb_rx_queue_setup, .rx_queue_release = eth_igb_rx_queue_release, .tx_queue_setup = eth_igb_tx_queue_setup, .tx_queue_release = eth_igb_tx_queue_release, .set_mc_addr_list = eth_igb_set_mc_addr_list, + .rxq_info_get = igb_rxq_info_get, + .txq_info_get = igb_txq_info_get, + .mac_addr_set = igbvf_default_mac_addr_set, + .get_reg_length = igbvf_get_reg_length, + .get_reg = igbvf_get_regs, +}; + +/* store statistics names and its offset in stats structure */ +struct rte_igb_xstats_name_off { + char name[RTE_ETH_XSTATS_NAME_SIZE]; + unsigned offset; +}; + +static const struct rte_igb_xstats_name_off rte_igb_stats_strings[] = { + {"rx_crc_errors", offsetof(struct e1000_hw_stats, crcerrs)}, + {"rx_align_errors", offsetof(struct e1000_hw_stats, algnerrc)}, + {"rx_symbol_errors", offsetof(struct e1000_hw_stats, symerrs)}, + {"rx_missed_packets", offsetof(struct e1000_hw_stats, mpc)}, + {"tx_single_collision_packets", offsetof(struct e1000_hw_stats, scc)}, + {"tx_multiple_collision_packets", offsetof(struct e1000_hw_stats, mcc)}, + {"tx_excessive_collision_packets", offsetof(struct e1000_hw_stats, + ecol)}, + {"tx_late_collisions", offsetof(struct e1000_hw_stats, latecol)}, + {"tx_total_collisions", offsetof(struct e1000_hw_stats, colc)}, + {"tx_deferred_packets", offsetof(struct e1000_hw_stats, dc)}, + {"tx_no_carrier_sense_packets", offsetof(struct e1000_hw_stats, tncrs)}, + {"rx_carrier_ext_errors", offsetof(struct e1000_hw_stats, cexterr)}, + {"rx_length_errors", offsetof(struct e1000_hw_stats, rlec)}, + {"rx_xon_packets", offsetof(struct e1000_hw_stats, xonrxc)}, + {"tx_xon_packets", offsetof(struct e1000_hw_stats, xontxc)}, + {"rx_xoff_packets", offsetof(struct e1000_hw_stats, xoffrxc)}, + {"tx_xoff_packets", offsetof(struct e1000_hw_stats, xofftxc)}, + {"rx_flow_control_unsupported_packets", offsetof(struct e1000_hw_stats, + fcruc)}, + {"rx_size_64_packets", offsetof(struct e1000_hw_stats, prc64)}, + {"rx_size_65_to_127_packets", offsetof(struct e1000_hw_stats, prc127)}, + {"rx_size_128_to_255_packets", offsetof(struct e1000_hw_stats, prc255)}, + {"rx_size_256_to_511_packets", offsetof(struct e1000_hw_stats, prc511)}, + {"rx_size_512_to_1023_packets", offsetof(struct e1000_hw_stats, + prc1023)}, + {"rx_size_1024_to_max_packets", offsetof(struct e1000_hw_stats, + prc1522)}, + {"rx_broadcast_packets", offsetof(struct e1000_hw_stats, bprc)}, + {"rx_multicast_packets", offsetof(struct e1000_hw_stats, mprc)}, + {"rx_undersize_errors", offsetof(struct e1000_hw_stats, ruc)}, + {"rx_fragment_errors", offsetof(struct e1000_hw_stats, rfc)}, + {"rx_oversize_errors", offsetof(struct e1000_hw_stats, roc)}, + {"rx_jabber_errors", offsetof(struct e1000_hw_stats, rjc)}, + {"rx_management_packets", offsetof(struct e1000_hw_stats, mgprc)}, + {"rx_management_dropped", offsetof(struct e1000_hw_stats, mgpdc)}, + {"tx_management_packets", offsetof(struct e1000_hw_stats, mgptc)}, + {"rx_total_packets", offsetof(struct e1000_hw_stats, tpr)}, + {"tx_total_packets", offsetof(struct e1000_hw_stats, tpt)}, + {"rx_total_bytes", offsetof(struct e1000_hw_stats, tor)}, + {"tx_total_bytes", offsetof(struct e1000_hw_stats, tot)}, + {"tx_size_64_packets", offsetof(struct e1000_hw_stats, ptc64)}, + {"tx_size_65_to_127_packets", offsetof(struct e1000_hw_stats, ptc127)}, + {"tx_size_128_to_255_packets", offsetof(struct e1000_hw_stats, ptc255)}, + {"tx_size_256_to_511_packets", offsetof(struct e1000_hw_stats, ptc511)}, + {"tx_size_512_to_1023_packets", offsetof(struct e1000_hw_stats, + ptc1023)}, + {"tx_size_1023_to_max_packets", offsetof(struct e1000_hw_stats, + ptc1522)}, + {"tx_multicast_packets", offsetof(struct e1000_hw_stats, mptc)}, + {"tx_broadcast_packets", offsetof(struct e1000_hw_stats, bptc)}, + {"tx_tso_packets", offsetof(struct e1000_hw_stats, tsctc)}, + {"tx_tso_errors", offsetof(struct e1000_hw_stats, tsctfc)}, + {"rx_sent_to_host_packets", offsetof(struct e1000_hw_stats, rpthc)}, + {"tx_sent_by_host_packets", offsetof(struct e1000_hw_stats, hgptc)}, + {"rx_code_violation_packets", offsetof(struct e1000_hw_stats, scvpc)}, + + {"interrupt_assert_count", offsetof(struct e1000_hw_stats, iac)}, +}; + +#define IGB_NB_XSTATS (sizeof(rte_igb_stats_strings) / \ + sizeof(rte_igb_stats_strings[0])) + +static const struct rte_igb_xstats_name_off rte_igbvf_stats_strings[] = { + {"rx_multicast_packets", offsetof(struct e1000_vf_stats, mprc)}, + {"rx_good_loopback_packets", offsetof(struct e1000_vf_stats, gprlbc)}, + {"tx_good_loopback_packets", offsetof(struct e1000_vf_stats, gptlbc)}, + {"rx_good_loopback_bytes", offsetof(struct e1000_vf_stats, gorlbc)}, + {"tx_good_loopback_bytes", offsetof(struct e1000_vf_stats, gotlbc)}, }; +#define IGBVF_NB_XSTATS (sizeof(rte_igbvf_stats_strings) / \ + sizeof(rte_igbvf_stats_strings[0])) + /** * Atomically reads the link status information from global * structure rte_eth_dev. @@ -467,12 +651,16 @@ eth_igb_dev_init(struct rte_eth_dev *eth_dev) struct e1000_hw *hw = E1000_DEV_PRIVATE_TO_HW(eth_dev->data->dev_private); struct e1000_vfta * shadow_vfta = - E1000_DEV_PRIVATE_TO_VFTA(eth_dev->data->dev_private); + E1000_DEV_PRIVATE_TO_VFTA(eth_dev->data->dev_private); struct e1000_filter_info *filter_info = E1000_DEV_PRIVATE_TO_FILTER_INFO(eth_dev->data->dev_private); + struct e1000_adapter *adapter = + E1000_DEV_PRIVATE(eth_dev->data->dev_private); + uint32_t ctrl_ext; pci_dev = eth_dev->pci_dev; + eth_dev->dev_ops = ð_igb_ops; eth_dev->rx_pkt_burst = ð_igb_recv_pkts; eth_dev->tx_pkt_burst = ð_igb_xmit_pkts; @@ -486,6 +674,8 @@ eth_igb_dev_init(struct rte_eth_dev *eth_dev) return 0; } + rte_eth_copy_pci_info(eth_dev, pci_dev); + hw->hw_addr= (void *)pci_dev->mem_resource[0].addr; igb_identify_hardware(eth_dev); @@ -572,6 +762,7 @@ eth_igb_dev_init(struct rte_eth_dev *eth_dev) goto err_late; } hw->mac.get_link_status = 1; + adapter->stopped = 0; /* Indicate SOL/IDER usage */ if (e1000_check_reset_block(hw) < 0) { @@ -588,15 +779,16 @@ eth_igb_dev_init(struct rte_eth_dev *eth_dev) E1000_WRITE_REG(hw, E1000_CTRL_EXT, ctrl_ext); E1000_WRITE_FLUSH(hw); - PMD_INIT_LOG(INFO, "port_id %d vendorID=0x%x deviceID=0x%x", + PMD_INIT_LOG(DEBUG, "port_id %d vendorID=0x%x deviceID=0x%x", eth_dev->data->port_id, pci_dev->id.vendor_id, pci_dev->id.device_id); - rte_intr_callback_register(&(pci_dev->intr_handle), - eth_igb_interrupt_handler, (void *)eth_dev); + rte_intr_callback_register(&pci_dev->intr_handle, + eth_igb_interrupt_handler, + (void *)eth_dev); - /* enable uio intr after callback register */ - rte_intr_enable(&(pci_dev->intr_handle)); + /* enable uio/vfio intr/eventfd mapping */ + rte_intr_enable(&pci_dev->intr_handle); /* enable support intr */ igb_intr_enable(eth_dev); @@ -613,7 +805,47 @@ eth_igb_dev_init(struct rte_eth_dev *eth_dev) err_late: igb_hw_control_release(hw); - return (error); + return error; +} + +static int +eth_igb_dev_uninit(struct rte_eth_dev *eth_dev) +{ + struct rte_pci_device *pci_dev; + struct e1000_hw *hw; + struct e1000_adapter *adapter = + E1000_DEV_PRIVATE(eth_dev->data->dev_private); + + PMD_INIT_FUNC_TRACE(); + + if (rte_eal_process_type() != RTE_PROC_PRIMARY) + return -EPERM; + + hw = E1000_DEV_PRIVATE_TO_HW(eth_dev->data->dev_private); + pci_dev = eth_dev->pci_dev; + + if (adapter->stopped == 0) + eth_igb_close(eth_dev); + + eth_dev->dev_ops = NULL; + eth_dev->rx_pkt_burst = NULL; + eth_dev->tx_pkt_burst = NULL; + + /* Reset any pending lock */ + igb_reset_swfw_lock(hw); + + rte_free(eth_dev->data->mac_addrs); + eth_dev->data->mac_addrs = NULL; + + /* uninitialize PF if max_vfs not zero */ + igb_pf_host_uninit(eth_dev); + + /* disable uio intr before callback unregister */ + rte_intr_disable(&(pci_dev->intr_handle)); + rte_intr_callback_unregister(&(pci_dev->intr_handle), + eth_igb_interrupt_handler, (void *)eth_dev); + + return 0; } /* @@ -623,9 +855,12 @@ static int eth_igbvf_dev_init(struct rte_eth_dev *eth_dev) { struct rte_pci_device *pci_dev; + struct e1000_adapter *adapter = + E1000_DEV_PRIVATE(eth_dev->data->dev_private); struct e1000_hw *hw = E1000_DEV_PRIVATE_TO_HW(eth_dev->data->dev_private); int diag; + struct ether_addr *perm_addr = (struct ether_addr *)hw->mac.perm_addr; PMD_INIT_FUNC_TRACE(); @@ -644,9 +879,12 @@ eth_igbvf_dev_init(struct rte_eth_dev *eth_dev) pci_dev = eth_dev->pci_dev; + rte_eth_copy_pci_info(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[0].addr; + adapter->stopped = 0; /* Initialize the shared code (base driver) */ diag = e1000_setup_init_funcs(hw, TRUE); @@ -675,6 +913,26 @@ eth_igbvf_dev_init(struct rte_eth_dev *eth_dev) return -ENOMEM; } + /* Generate a random MAC address, if none was assigned by PF. */ + if (is_zero_ether_addr(perm_addr)) { + eth_random_addr(perm_addr->addr_bytes); + diag = e1000_rar_set(hw, perm_addr->addr_bytes, 0); + if (diag) { + rte_free(eth_dev->data->mac_addrs); + eth_dev->data->mac_addrs = NULL; + return diag; + } + PMD_INIT_LOG(INFO, "\tVF MAC address not assigned by Host PF"); + PMD_INIT_LOG(INFO, "\tAssign randomly generated MAC address " + "%02x:%02x:%02x:%02x:%02x:%02x", + 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]); @@ -687,13 +945,39 @@ eth_igbvf_dev_init(struct rte_eth_dev *eth_dev) return 0; } +static int +eth_igbvf_dev_uninit(struct rte_eth_dev *eth_dev) +{ + struct e1000_adapter *adapter = + E1000_DEV_PRIVATE(eth_dev->data->dev_private); + + PMD_INIT_FUNC_TRACE(); + + if (rte_eal_process_type() != RTE_PROC_PRIMARY) + return -EPERM; + + if (adapter->stopped == 0) + igbvf_dev_close(eth_dev); + + eth_dev->dev_ops = NULL; + eth_dev->rx_pkt_burst = NULL; + eth_dev->tx_pkt_burst = NULL; + + rte_free(eth_dev->data->mac_addrs); + eth_dev->data->mac_addrs = NULL; + + return 0; +} + static struct eth_driver rte_igb_pmd = { .pci_drv = { .name = "rte_igb_pmd", .id_table = pci_id_igb_map, - .drv_flags = RTE_PCI_DRV_NEED_MAPPING | RTE_PCI_DRV_INTR_LSC, + .drv_flags = RTE_PCI_DRV_NEED_MAPPING | RTE_PCI_DRV_INTR_LSC | + RTE_PCI_DRV_DETACHABLE, }, .eth_dev_init = eth_igb_dev_init, + .eth_dev_uninit = eth_igb_dev_uninit, .dev_private_size = sizeof(struct e1000_adapter), }; @@ -704,9 +988,10 @@ static struct eth_driver rte_igbvf_pmd = { .pci_drv = { .name = "rte_igbvf_pmd", .id_table = pci_id_igbvf_map, - .drv_flags = RTE_PCI_DRV_NEED_MAPPING, + .drv_flags = RTE_PCI_DRV_NEED_MAPPING | RTE_PCI_DRV_DETACHABLE, }, .eth_dev_init = eth_igbvf_dev_init, + .eth_dev_uninit = eth_igbvf_dev_uninit, .dev_private_size = sizeof(struct e1000_adapter), }; @@ -739,7 +1024,79 @@ rte_igbvf_pmd_init(const char *name __rte_unused, const char *params __rte_unuse PMD_INIT_FUNC_TRACE(); rte_eth_driver_register(&rte_igbvf_pmd); - return (0); + return 0; +} + +static int +igb_check_mq_mode(struct rte_eth_dev *dev) +{ + enum rte_eth_rx_mq_mode rx_mq_mode = dev->data->dev_conf.rxmode.mq_mode; + enum rte_eth_tx_mq_mode tx_mq_mode = dev->data->dev_conf.txmode.mq_mode; + uint16_t nb_rx_q = dev->data->nb_rx_queues; + uint16_t nb_tx_q = dev->data->nb_rx_queues; + + if ((rx_mq_mode & ETH_MQ_RX_DCB_FLAG) || + tx_mq_mode == ETH_MQ_TX_DCB || + tx_mq_mode == ETH_MQ_TX_VMDQ_DCB) { + PMD_INIT_LOG(ERR, "DCB mode is not supported."); + return -EINVAL; + } + if (RTE_ETH_DEV_SRIOV(dev).active != 0) { + /* Check multi-queue mode. + * To no break software we accept ETH_MQ_RX_NONE as this might + * be used to turn off VLAN filter. + */ + + if (rx_mq_mode == ETH_MQ_RX_NONE || + rx_mq_mode == ETH_MQ_RX_VMDQ_ONLY) { + dev->data->dev_conf.rxmode.mq_mode = ETH_MQ_RX_VMDQ_ONLY; + RTE_ETH_DEV_SRIOV(dev).nb_q_per_pool = 1; + } else { + /* Only support one queue on VFs. + * RSS together with SRIOV is not supported. + */ + PMD_INIT_LOG(ERR, "SRIOV is active," + " wrong mq_mode rx %d.", + rx_mq_mode); + return -EINVAL; + } + /* TX mode is not used here, so mode might be ignored.*/ + if (tx_mq_mode != ETH_MQ_TX_VMDQ_ONLY) { + /* SRIOV only works in VMDq enable mode */ + PMD_INIT_LOG(WARNING, "SRIOV is active," + " TX mode %d is not supported. " + " Driver will behave as %d mode.", + tx_mq_mode, ETH_MQ_TX_VMDQ_ONLY); + } + + /* check valid queue number */ + if ((nb_rx_q > 1) || (nb_tx_q > 1)) { + PMD_INIT_LOG(ERR, "SRIOV is active," + " only support one queue on VFs."); + return -EINVAL; + } + } else { + /* To no break software that set invalid mode, only display + * warning if invalid mode is used. + */ + if (rx_mq_mode != ETH_MQ_RX_NONE && + rx_mq_mode != ETH_MQ_RX_VMDQ_ONLY && + rx_mq_mode != ETH_MQ_RX_RSS) { + /* RSS together with VMDq not supported*/ + PMD_INIT_LOG(ERR, "RX mode %d is not supported.", + rx_mq_mode); + return -EINVAL; + } + + if (tx_mq_mode != ETH_MQ_TX_NONE && + tx_mq_mode != ETH_MQ_TX_VMDQ_ONLY) { + PMD_INIT_LOG(WARNING, "TX mode %d is not supported." + " Due to txmode is meaningless in this" + " driver, just ignore.", + tx_mq_mode); + } + } + return 0; } static int @@ -747,12 +1104,22 @@ eth_igb_configure(struct rte_eth_dev *dev) { struct e1000_interrupt *intr = E1000_DEV_PRIVATE_TO_INTR(dev->data->dev_private); + int ret; PMD_INIT_FUNC_TRACE(); + + /* multipe queue mode checking */ + ret = igb_check_mq_mode(dev); + if (ret != 0) { + PMD_DRV_LOG(ERR, "igb_check_mq_mode fails with %d.", + ret); + return ret; + } + intr->flags |= E1000_FLAG_NEED_LINK_UPDATE; PMD_INIT_FUNC_TRACE(); - return (0); + return 0; } static int @@ -760,11 +1127,18 @@ eth_igb_start(struct rte_eth_dev *dev) { struct e1000_hw *hw = E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private); - int ret, i, mask; + struct e1000_adapter *adapter = + E1000_DEV_PRIVATE(dev->data->dev_private); + struct rte_intr_handle *intr_handle = &dev->pci_dev->intr_handle; + int ret, mask; + uint32_t intr_vector = 0; uint32_t ctrl_ext; PMD_INIT_FUNC_TRACE(); + /* disable uio/vfio intr/eventfd mapping */ + rte_intr_disable(intr_handle); + /* Power up the phy. Needed to make the link go Up */ e1000_power_up_phy(hw); @@ -786,8 +1160,9 @@ eth_igb_start(struct rte_eth_dev *dev) /* Initialize the hardware */ if (igb_hardware_init(hw)) { PMD_INIT_LOG(ERR, "Unable to initialize the hardware"); - return (-EIO); + return -EIO; } + adapter->stopped = 0; E1000_WRITE_REG(hw, E1000_VET, ETHER_TYPE_VLAN << 16 | ETHER_TYPE_VLAN); @@ -800,6 +1175,29 @@ eth_igb_start(struct rte_eth_dev *dev) /* configure PF module if SRIOV enabled */ igb_pf_host_configure(dev); + /* check and configure queue intr-vector mapping */ + if ((rte_intr_cap_multiple(intr_handle) || + !RTE_ETH_DEV_SRIOV(dev).active) && + dev->data->dev_conf.intr_conf.rxq != 0) { + intr_vector = dev->data->nb_rx_queues; + if (rte_intr_efd_enable(intr_handle, intr_vector)) + return -1; + } + + if (rte_intr_dp_is_en(intr_handle) && !intr_handle->intr_vec) { + intr_handle->intr_vec = + rte_zmalloc("intr_vec", + dev->data->nb_rx_queues * sizeof(int), 0); + if (intr_handle->intr_vec == NULL) { + PMD_INIT_LOG(ERR, "Failed to allocate %d rx_queues" + " intr_vec\n", dev->data->nb_rx_queues); + return -ENOMEM; + } + } + + /* confiugre msix for rx interrupt */ + eth_igb_configure_msix_intr(dev); + /* Configure for OS presence */ igb_init_manageability(hw); @@ -827,33 +1225,9 @@ eth_igb_start(struct rte_eth_dev *dev) igb_vmdq_vlan_hw_filter_enable(dev); } - /* - * Configure the Interrupt Moderation register (EITR) with the maximum - * possible value (0xFFFF) to minimize "System Partial Write" issued by - * spurious [DMA] memory updates of RX and TX ring descriptors. - * - * With a EITR granularity of 2 microseconds in the 82576, only 7/8 - * spurious memory updates per second should be expected. - * ((65535 * 2) / 1000.1000 ~= 0.131 second). - * - * Because interrupts are not used at all, the MSI-X is not activated - * and interrupt moderation is controlled by EITR[0]. - * - * Note that having [almost] disabled memory updates of RX and TX ring - * descriptors through the Interrupt Moderation mechanism, memory - * updates of ring descriptors are now moderated by the configurable - * value of Write-Back Threshold registers. - */ if ((hw->mac.type == e1000_82576) || (hw->mac.type == e1000_82580) || (hw->mac.type == e1000_i350) || (hw->mac.type == e1000_i210) || (hw->mac.type == e1000_i211)) { - uint32_t ivar; - - /* Enable all RX & TX queues in the IVAR registers */ - ivar = (uint32_t) ((E1000_IVAR_VALID << 16) | E1000_IVAR_VALID); - for (i = 0; i < 8; i++) - E1000_WRITE_REG_ARRAY(hw, E1000_IVAR0, i, ivar); - /* Configure EITR with the maximum possible value (0xFFFF) */ E1000_WRITE_REG(hw, E1000_EITR(0), 0xFFFF); } @@ -903,23 +1277,40 @@ eth_igb_start(struct rte_eth_dev *dev) } e1000_setup_link(hw); - /* check if lsc interrupt feature is enabled */ - if (dev->data->dev_conf.intr_conf.lsc != 0) - ret = eth_igb_lsc_interrupt_setup(dev); + if (rte_intr_allow_others(intr_handle)) { + /* check if lsc interrupt is enabled */ + if (dev->data->dev_conf.intr_conf.lsc != 0) + eth_igb_lsc_interrupt_setup(dev); + } else { + rte_intr_callback_unregister(intr_handle, + eth_igb_interrupt_handler, + (void *)dev); + if (dev->data->dev_conf.intr_conf.lsc != 0) + PMD_INIT_LOG(INFO, "lsc won't enable because of" + " no intr multiplex\n"); + } + + /* check if rxq interrupt is enabled */ + if (dev->data->dev_conf.intr_conf.rxq != 0 && + rte_intr_dp_is_en(intr_handle)) + eth_igb_rxq_interrupt_setup(dev); + + /* enable uio/vfio intr/eventfd mapping */ + rte_intr_enable(intr_handle); /* resume enabled intr since hw reset */ igb_intr_enable(dev); PMD_INIT_LOG(DEBUG, "<<"); - return (0); + return 0; error_invalid_config: PMD_INIT_LOG(ERR, "Invalid link_speed/link_duplex (%u/%u) for port %u", dev->data->dev_conf.link_speed, dev->data->dev_conf.link_duplex, dev->data->port_id); igb_dev_clear_queues(dev); - return (-EINVAL); + return -EINVAL; } /********************************************************************* @@ -938,8 +1329,13 @@ eth_igb_stop(struct rte_eth_dev *dev) struct e1000_flex_filter *p_flex; struct e1000_5tuple_filter *p_5tuple, *p_5tuple_next; struct e1000_2tuple_filter *p_2tuple, *p_2tuple_next; + struct rte_intr_handle *intr_handle = &dev->pci_dev->intr_handle; igb_intr_disable(hw); + + /* disable intr eventfd mapping */ + rte_intr_disable(intr_handle); + igb_pf_reset_hw(hw); E1000_WRITE_REG(hw, E1000_WUC, 0); @@ -988,15 +1384,33 @@ eth_igb_stop(struct rte_eth_dev *dev) rte_free(p_2tuple); } filter_info->twotuple_mask = 0; + + if (!rte_intr_allow_others(intr_handle)) + /* resume to the default handler */ + rte_intr_callback_register(intr_handle, + eth_igb_interrupt_handler, + (void *)dev); + + /* Clean datapath event and queue/vec mapping */ + rte_intr_efd_disable(intr_handle); + if (intr_handle->intr_vec != NULL) { + rte_free(intr_handle->intr_vec); + intr_handle->intr_vec = NULL; + } } static void eth_igb_close(struct rte_eth_dev *dev) { struct e1000_hw *hw = E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private); + struct e1000_adapter *adapter = + E1000_DEV_PRIVATE(dev->data->dev_private); struct rte_eth_link link; + struct rte_pci_device *pci_dev; eth_igb_stop(dev); + adapter->stopped = 1; + e1000_phy_hw_reset(hw); igb_release_manageability(hw); igb_hw_control_release(hw); @@ -1010,7 +1424,13 @@ eth_igb_close(struct rte_eth_dev *dev) E1000_WRITE_REG(hw, E1000_82580_PHY_POWER_MGMT, phpm_reg); } - igb_dev_clear_queues(dev); + igb_dev_free_queues(dev); + + pci_dev = dev->pci_dev; + if (pci_dev->intr_handle.intr_vec) { + rte_free(pci_dev->intr_handle.intr_vec); + pci_dev->intr_handle.intr_vec = NULL; + } memset(&link, 0, sizeof(link)); rte_igb_dev_atomic_write_link_status(dev, &link); @@ -1083,24 +1503,28 @@ igb_hardware_init(struct e1000_hw *hw) diag = e1000_init_hw(hw); if (diag < 0) - return (diag); + return diag; E1000_WRITE_REG(hw, E1000_VET, ETHER_TYPE_VLAN << 16 | ETHER_TYPE_VLAN); e1000_get_phy_info(hw); e1000_check_for_link(hw); - return (0); + return 0; } /* This function is based on igb_update_stats_counters() in igb/if_igb.c */ static void -eth_igb_stats_get(struct rte_eth_dev *dev, struct rte_eth_stats *rte_stats) +igb_read_stats_registers(struct e1000_hw *hw, struct e1000_hw_stats *stats) { - struct e1000_hw *hw = E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private); - struct e1000_hw_stats *stats = - E1000_DEV_PRIVATE_TO_STATS(dev->data->dev_private); int pause_frames; + uint64_t old_gprc = stats->gprc; + uint64_t old_gptc = stats->gptc; + uint64_t old_tpr = stats->tpr; + uint64_t old_tpt = stats->tpt; + uint64_t old_rpthc = stats->rpthc; + uint64_t old_hgptc = stats->hgptc; + if(hw->phy.media_type == e1000_media_type_copper || (E1000_READ_REG(hw, E1000_STATUS) & E1000_STATUS_LU)) { stats->symerrs += @@ -1142,10 +1566,13 @@ eth_igb_stats_get(struct rte_eth_dev *dev, struct rte_eth_stats *rte_stats) /* For the 64-bit byte counters the low dword must be read first. */ /* Both registers clear on the read of the high dword */ + /* Workaround CRC bytes included in size, take away 4 bytes/packet */ stats->gorc += E1000_READ_REG(hw, E1000_GORCL); stats->gorc += ((uint64_t)E1000_READ_REG(hw, E1000_GORCH) << 32); + stats->gorc -= (stats->gprc - old_gprc) * ETHER_CRC_LEN; stats->gotc += E1000_READ_REG(hw, E1000_GOTCL); stats->gotc += ((uint64_t)E1000_READ_REG(hw, E1000_GOTCH) << 32); + stats->gotc -= (stats->gptc - old_gptc) * ETHER_CRC_LEN; stats->rnbc += E1000_READ_REG(hw, E1000_RNBC); stats->ruc += E1000_READ_REG(hw, E1000_RUC); @@ -1153,11 +1580,16 @@ eth_igb_stats_get(struct rte_eth_dev *dev, struct rte_eth_stats *rte_stats) stats->roc += E1000_READ_REG(hw, E1000_ROC); stats->rjc += E1000_READ_REG(hw, E1000_RJC); - stats->tor += E1000_READ_REG(hw, E1000_TORH); - stats->tot += E1000_READ_REG(hw, E1000_TOTH); - stats->tpr += E1000_READ_REG(hw, E1000_TPR); stats->tpt += E1000_READ_REG(hw, E1000_TPT); + + stats->tor += E1000_READ_REG(hw, E1000_TORL); + stats->tor += ((uint64_t)E1000_READ_REG(hw, E1000_TORH) << 32); + stats->tor -= (stats->tpr - old_tpr) * ETHER_CRC_LEN; + stats->tot += E1000_READ_REG(hw, E1000_TOTL); + stats->tot += ((uint64_t)E1000_READ_REG(hw, E1000_TOTH) << 32); + stats->tot -= (stats->tpt - old_tpt) * ETHER_CRC_LEN; + stats->ptc64 += E1000_READ_REG(hw, E1000_PTC64); stats->ptc127 += E1000_READ_REG(hw, E1000_PTC127); stats->ptc255 += E1000_READ_REG(hw, E1000_PTC255); @@ -1190,8 +1622,10 @@ eth_igb_stats_get(struct rte_eth_dev *dev, struct rte_eth_stats *rte_stats) stats->htcbdpc += E1000_READ_REG(hw, E1000_HTCBDPC); stats->hgorc += E1000_READ_REG(hw, E1000_HGORCL); stats->hgorc += ((uint64_t)E1000_READ_REG(hw, E1000_HGORCH) << 32); + stats->hgorc -= (stats->rpthc - old_rpthc) * ETHER_CRC_LEN; stats->hgotc += E1000_READ_REG(hw, E1000_HGOTCL); stats->hgotc += ((uint64_t)E1000_READ_REG(hw, E1000_HGOTCH) << 32); + stats->hgotc -= (stats->hgptc - old_hgptc) * ETHER_CRC_LEN; stats->lenerrs += E1000_READ_REG(hw, E1000_LENERRS); stats->scvpc += E1000_READ_REG(hw, E1000_SCVPC); stats->hrmpc += E1000_READ_REG(hw, E1000_HRMPC); @@ -1202,28 +1636,29 @@ eth_igb_stats_get(struct rte_eth_dev *dev, struct rte_eth_stats *rte_stats) stats->cexterr += E1000_READ_REG(hw, E1000_CEXTERR); stats->tsctc += E1000_READ_REG(hw, E1000_TSCTC); stats->tsctfc += E1000_READ_REG(hw, E1000_TSCTFC); +} + +static void +eth_igb_stats_get(struct rte_eth_dev *dev, struct rte_eth_stats *rte_stats) +{ + struct e1000_hw *hw = E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private); + struct e1000_hw_stats *stats = + E1000_DEV_PRIVATE_TO_STATS(dev->data->dev_private); + + igb_read_stats_registers(hw, stats); if (rte_stats == NULL) return; /* Rx Errors */ - rte_stats->ibadcrc = stats->crcerrs; - rte_stats->ibadlen = stats->rlec + stats->ruc + stats->roc; rte_stats->imissed = stats->mpc; - rte_stats->ierrors = rte_stats->ibadcrc + - rte_stats->ibadlen + - rte_stats->imissed + + rte_stats->ierrors = stats->crcerrs + + stats->rlec + stats->ruc + stats->roc + stats->rxerrc + stats->algnerrc + stats->cexterr; /* Tx Errors */ rte_stats->oerrors = stats->ecol + stats->latecol; - /* XON/XOFF pause frames */ - rte_stats->tx_pause_xon = stats->xontxc; - rte_stats->rx_pause_xon = stats->xonrxc; - rte_stats->tx_pause_xoff = stats->xofftxc; - rte_stats->rx_pause_xoff = stats->xoffrxc; - rte_stats->ipackets = stats->gprc; rte_stats->opackets = stats->gptc; rte_stats->ibytes = stats->gorc; @@ -1244,12 +1679,52 @@ eth_igb_stats_reset(struct rte_eth_dev *dev) } static void -eth_igbvf_stats_get(struct rte_eth_dev *dev, struct rte_eth_stats *rte_stats) +eth_igb_xstats_reset(struct rte_eth_dev *dev) +{ + struct e1000_hw_stats *stats = + E1000_DEV_PRIVATE_TO_STATS(dev->data->dev_private); + + /* HW registers are cleared on read */ + eth_igb_xstats_get(dev, NULL, IGB_NB_XSTATS); + + /* Reset software totals */ + memset(stats, 0, sizeof(*stats)); +} + +static int +eth_igb_xstats_get(struct rte_eth_dev *dev, struct rte_eth_xstats *xstats, + unsigned n) { struct e1000_hw *hw = E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private); - struct e1000_vf_stats *hw_stats = (struct e1000_vf_stats*) - E1000_DEV_PRIVATE_TO_STATS(dev->data->dev_private); + struct e1000_hw_stats *hw_stats = + E1000_DEV_PRIVATE_TO_STATS(dev->data->dev_private); + unsigned i; + + if (n < IGB_NB_XSTATS) + return IGB_NB_XSTATS; + + igb_read_stats_registers(hw, hw_stats); + + /* If this is a reset xstats is NULL, and we have cleared the + * registers by reading them. + */ + if (!xstats) + return 0; + + /* Extended stats */ + for (i = 0; i < IGB_NB_XSTATS; i++) { + snprintf(xstats[i].name, sizeof(xstats[i].name), + "%s", rte_igb_stats_strings[i].name); + xstats[i].value = *(uint64_t *)(((char *)hw_stats) + + rte_igb_stats_strings[i].offset); + } + return IGB_NB_XSTATS; +} + +static void +igbvf_read_stats_registers(struct e1000_hw *hw, struct e1000_vf_stats *hw_stats) +{ /* Good Rx packets, include VF loopback */ UPDATE_VF_STAT(E1000_VFGPRC, hw_stats->last_gprc, hw_stats->gprc); @@ -1285,6 +1760,43 @@ eth_igbvf_stats_get(struct rte_eth_dev *dev, struct rte_eth_stats *rte_stats) /* Good Tx loopback octets */ UPDATE_VF_STAT(E1000_VFGOTLBC, hw_stats->last_gotlbc, hw_stats->gotlbc); +} + +static int +eth_igbvf_xstats_get(struct rte_eth_dev *dev, struct rte_eth_xstats *xstats, + unsigned n) +{ + struct e1000_hw *hw = E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private); + struct e1000_vf_stats *hw_stats = (struct e1000_vf_stats *) + E1000_DEV_PRIVATE_TO_STATS(dev->data->dev_private); + unsigned i; + + if (n < IGBVF_NB_XSTATS) + return IGBVF_NB_XSTATS; + + igbvf_read_stats_registers(hw, hw_stats); + + if (!xstats) + return 0; + + for (i = 0; i < IGBVF_NB_XSTATS; i++) { + snprintf(xstats[i].name, sizeof(xstats[i].name), "%s", + rte_igbvf_stats_strings[i].name); + xstats[i].value = *(uint64_t *)(((char *)hw_stats) + + rte_igbvf_stats_strings[i].offset); + } + + return IGBVF_NB_XSTATS; +} + +static void +eth_igbvf_stats_get(struct rte_eth_dev *dev, struct rte_eth_stats *rte_stats) +{ + struct e1000_hw *hw = E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private); + struct e1000_vf_stats *hw_stats = (struct e1000_vf_stats *) + E1000_DEV_PRIVATE_TO_STATS(dev->data->dev_private); + + igbvf_read_stats_registers(hw, hw_stats); if (rte_stats == NULL) return; @@ -1298,7 +1810,6 @@ eth_igbvf_stats_get(struct rte_eth_dev *dev, struct rte_eth_stats *rte_stats) rte_stats->ilbbytes = hw_stats->gorlbc; rte_stats->olbpackets = hw_stats->gptlbc; rte_stats->olbbytes = hw_stats->gotlbc; - } static void @@ -1313,7 +1824,6 @@ eth_igbvf_stats_reset(struct rte_eth_dev *dev) /* reset HW current stats*/ memset(&hw_stats->gprc, 0, sizeof(*hw_stats) - offsetof(struct e1000_vf_stats, gprc)); - } static void @@ -1334,7 +1844,8 @@ eth_igb_infos_get(struct rte_eth_dev *dev, struct rte_eth_dev_info *dev_info) DEV_TX_OFFLOAD_IPV4_CKSUM | DEV_TX_OFFLOAD_UDP_CKSUM | DEV_TX_OFFLOAD_TCP_CKSUM | - DEV_TX_OFFLOAD_SCTP_CKSUM; + DEV_TX_OFFLOAD_SCTP_CKSUM | + DEV_TX_OFFLOAD_TCP_TSO; switch (hw->mac.type) { case e1000_82575: @@ -1407,6 +1918,36 @@ eth_igb_infos_get(struct rte_eth_dev *dev, struct rte_eth_dev_info *dev_info) }, .txq_flags = 0, }; + + dev_info->rx_desc_lim = rx_desc_lim; + dev_info->tx_desc_lim = tx_desc_lim; +} + +static const uint32_t * +eth_igb_supported_ptypes_get(struct rte_eth_dev *dev) +{ + static const uint32_t ptypes[] = { + /* refers to igb_rxd_pkt_info_to_pkt_type() */ + RTE_PTYPE_L2_ETHER, + RTE_PTYPE_L3_IPV4, + RTE_PTYPE_L3_IPV4_EXT, + RTE_PTYPE_L3_IPV6, + RTE_PTYPE_L3_IPV6_EXT, + RTE_PTYPE_L4_TCP, + RTE_PTYPE_L4_UDP, + RTE_PTYPE_L4_SCTP, + RTE_PTYPE_TUNNEL_IP, + RTE_PTYPE_INNER_L3_IPV6, + RTE_PTYPE_INNER_L3_IPV6_EXT, + RTE_PTYPE_INNER_L4_TCP, + RTE_PTYPE_INNER_L4_UDP, + RTE_PTYPE_UNKNOWN + }; + + if (dev->rx_pkt_burst == eth_igb_recv_pkts || + dev->rx_pkt_burst == eth_igb_recv_scattered_pkts) + return ptypes; + return NULL; } static void @@ -1425,7 +1966,8 @@ eth_igbvf_infos_get(struct rte_eth_dev *dev, struct rte_eth_dev_info *dev_info) DEV_TX_OFFLOAD_IPV4_CKSUM | DEV_TX_OFFLOAD_UDP_CKSUM | DEV_TX_OFFLOAD_TCP_CKSUM | - DEV_TX_OFFLOAD_SCTP_CKSUM; + DEV_TX_OFFLOAD_SCTP_CKSUM | + DEV_TX_OFFLOAD_TCP_TSO; switch (hw->mac.type) { case e1000_vfadapt: dev_info->max_rx_queues = 2; @@ -1458,6 +2000,9 @@ eth_igbvf_infos_get(struct rte_eth_dev *dev, struct rte_eth_dev_info *dev_info) }, .txq_flags = 0, }; + + dev_info->rx_desc_lim = rx_desc_lim; + dev_info->tx_desc_lim = tx_desc_lim; } /* return 0 means link status changed, -1 means not changed */ @@ -1514,11 +2059,11 @@ eth_igb_link_update(struct rte_eth_dev *dev, int wait_to_complete) if (link_check) { hw->mac.ops.get_link_up_info(hw, &link.link_speed, &link.link_duplex); - link.link_status = 1; + link.link_status = ETH_LINK_UP; } else if (!link_check) { link.link_speed = 0; link.link_duplex = 0; - link.link_status = 0; + link.link_status = ETH_LINK_DOWN; } rte_igb_dev_atomic_write_link_status(dev, &link); @@ -1679,15 +2224,28 @@ eth_igb_vlan_filter_set(struct rte_eth_dev *dev, uint16_t vlan_id, int on) return 0; } -static void -eth_igb_vlan_tpid_set(struct rte_eth_dev *dev, uint16_t tpid) +static int +eth_igb_vlan_tpid_set(struct rte_eth_dev *dev, + enum rte_vlan_type vlan_type, + uint16_t tpid) { struct e1000_hw *hw = E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private); - uint32_t reg = ETHER_TYPE_VLAN ; + uint32_t reg = ETHER_TYPE_VLAN; + int ret = 0; + + switch (vlan_type) { + case ETH_VLAN_TYPE_INNER: + reg |= (tpid << 16); + E1000_WRITE_REG(hw, E1000_VET, reg); + break; + default: + ret = -EINVAL; + PMD_DRV_LOG(ERR, "Unsupported vlan type %d\n", vlan_type); + break; + } - reg |= (tpid << 16); - E1000_WRITE_REG(hw, E1000_VET, reg); + return ret; } static void @@ -1836,6 +2394,33 @@ eth_igb_lsc_interrupt_setup(struct rte_eth_dev *dev) return 0; } +/* It clears the interrupt causes and enables the interrupt. + * It will be called once only during nic initialized. + * + * @param dev + * Pointer to struct rte_eth_dev. + * + * @return + * - On success, zero. + * - On failure, a negative value. + */ +static int eth_igb_rxq_interrupt_setup(struct rte_eth_dev *dev) +{ + uint32_t mask, regval; + struct e1000_hw *hw = + E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private); + struct rte_eth_dev_info dev_info; + + memset(&dev_info, 0, sizeof(dev_info)); + eth_igb_infos_get(dev, &dev_info); + + mask = 0xFFFFFFFF >> (32 - dev_info.max_rx_queues); + regval = E1000_READ_REG(hw, E1000_EIMS); + E1000_WRITE_REG(hw, E1000_EIMS, regval | mask); + + return 0; +} + /* * It reads ICR and gets interrupt causes, check it and set a bit flag * to update link status. @@ -1925,7 +2510,8 @@ eth_igb_interrupt_action(struct rte_eth_dev *dev) PMD_INIT_LOG(INFO, " Port %d: Link Down", dev->data->port_id); } - PMD_INIT_LOG(INFO, "PCI Address: %04d:%02d:%02d:%d", + + PMD_INIT_LOG(DEBUG, "PCI Address: %04d:%02d:%02d:%d", dev->pci_dev->addr.domain, dev->pci_dev->addr.bus, dev->pci_dev->addr.devid, @@ -1977,7 +2563,7 @@ eth_igb_led_on(struct rte_eth_dev *dev) struct e1000_hw *hw; hw = E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private); - return (e1000_led_on(hw) == E1000_SUCCESS ? 0 : -ENOTSUP); + return e1000_led_on(hw) == E1000_SUCCESS ? 0 : -ENOTSUP; } static int @@ -1986,7 +2572,7 @@ eth_igb_led_off(struct rte_eth_dev *dev) struct e1000_hw *hw; hw = E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private); - return (e1000_led_off(hw) == E1000_SUCCESS ? 0 : -ENOTSUP); + return e1000_led_off(hw) == E1000_SUCCESS ? 0 : -ENOTSUP; } static int @@ -2058,7 +2644,7 @@ eth_igb_flow_ctrl_set(struct rte_eth_dev *dev, struct rte_eth_fc_conf *fc_conf) (fc_conf->high_water < fc_conf->low_water)) { PMD_INIT_LOG(ERR, "e1000 incorrect high/low water value"); PMD_INIT_LOG(ERR, "high water must <= 0x%x", max_high_water); - return (-EINVAL); + return -EINVAL; } hw->fc.requested_mode = rte_fcmode_2_e1000_fcmode[fc_conf->mode]; @@ -2088,7 +2674,7 @@ eth_igb_flow_ctrl_set(struct rte_eth_dev *dev, struct rte_eth_fc_conf *fc_conf) } PMD_INIT_LOG(ERR, "e1000_setup_link_generic = 0x%x", err); - return (-EIO); + return -EIO; } #define E1000_RAH_POOLSEL_SHIFT (18) @@ -2116,6 +2702,14 @@ eth_igb_rar_clear(struct rte_eth_dev *dev, uint32_t index) e1000_rar_set(hw, addr, index); } +static void +eth_igb_default_mac_addr_set(struct rte_eth_dev *dev, + struct ether_addr *addr) +{ + eth_igb_rar_clear(dev, 0); + + eth_igb_rar_set(dev, (void *)addr, 0, 0); +} /* * Virtual Function operations */ @@ -2213,12 +2807,12 @@ igbvf_dev_configure(struct rte_eth_dev *dev) */ #ifndef RTE_LIBRTE_E1000_PF_DISABLE_STRIP_CRC if (!conf->rxmode.hw_strip_crc) { - PMD_INIT_LOG(INFO, "VF can't disable HW CRC Strip"); + PMD_INIT_LOG(NOTICE, "VF can't disable HW CRC Strip"); conf->rxmode.hw_strip_crc = 1; } #else if (conf->rxmode.hw_strip_crc) { - PMD_INIT_LOG(INFO, "VF can't enable HW CRC Strip"); + PMD_INIT_LOG(NOTICE, "VF can't enable HW CRC Strip"); conf->rxmode.hw_strip_crc = 0; } #endif @@ -2231,11 +2825,14 @@ igbvf_dev_start(struct rte_eth_dev *dev) { struct e1000_hw *hw = E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private); + struct e1000_adapter *adapter = + E1000_DEV_PRIVATE(dev->data->dev_private); int ret; PMD_INIT_FUNC_TRACE(); hw->mac.ops.reset_hw(hw); + adapter->stopped = 0; /* Set all vfta */ igbvf_set_vfta_all(dev,1); @@ -2273,18 +2870,74 @@ static void igbvf_dev_close(struct rte_eth_dev *dev) { struct e1000_hw *hw = E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private); + struct e1000_adapter *adapter = + E1000_DEV_PRIVATE(dev->data->dev_private); + struct ether_addr addr; PMD_INIT_FUNC_TRACE(); e1000_reset_hw(hw); igbvf_dev_stop(dev); + adapter->stopped = 1; + igb_dev_free_queues(dev); + + /** + * reprogram the RAR with a zero mac address, + * to ensure that the VF traffic goes to the PF + * after stop, close and detach of the VF. + **/ + + memset(&addr, 0, sizeof(addr)); + igbvf_default_mac_addr_set(dev, &addr); +} + +static void +igbvf_promiscuous_enable(struct rte_eth_dev *dev) +{ + struct e1000_hw *hw = E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private); + + /* Set both unicast and multicast promisc */ + e1000_promisc_set_vf(hw, e1000_promisc_enabled); +} + +static void +igbvf_promiscuous_disable(struct rte_eth_dev *dev) +{ + struct e1000_hw *hw = E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private); + + /* If in allmulticast mode leave multicast promisc */ + if (dev->data->all_multicast == 1) + e1000_promisc_set_vf(hw, e1000_promisc_multicast); + else + e1000_promisc_set_vf(hw, e1000_promisc_disabled); +} + +static void +igbvf_allmulticast_enable(struct rte_eth_dev *dev) +{ + struct e1000_hw *hw = E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private); + + /* In promiscuous mode multicast promisc already set */ + if (dev->data->promiscuous == 0) + e1000_promisc_set_vf(hw, e1000_promisc_multicast); +} + +static void +igbvf_allmulticast_disable(struct rte_eth_dev *dev) +{ + struct e1000_hw *hw = E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private); + + /* In promiscuous mode leave multicast promisc enabled */ + if (dev->data->promiscuous == 0) + e1000_promisc_set_vf(hw, e1000_promisc_disabled); } static int igbvf_set_vfta(struct e1000_hw *hw, uint16_t vid, bool on) { struct e1000_mbx_info *mbx = &hw->mbx; uint32_t msgbuf[2]; + s32 err; /* After set vlan, vlan strip will also be enabled in igb driver*/ msgbuf[0] = E1000_VF_SET_VLAN; @@ -2293,8 +2946,21 @@ static int igbvf_set_vfta(struct e1000_hw *hw, uint16_t vid, bool on) if (on) msgbuf[0] |= E1000_VF_SET_VLAN_ADD; - return (mbx->ops.write_posted(hw, msgbuf, 2, 0)); -} + err = mbx->ops.write_posted(hw, msgbuf, 2, 0); + if (err) + goto mbx_err; + + err = mbx->ops.read_posted(hw, msgbuf, 2, 0); + if (err) + goto mbx_err; + + msgbuf[0] &= ~E1000_VT_MSGTYPE_CTS; + if (msgbuf[0] == (E1000_VF_SET_VLAN | E1000_VT_MSGTYPE_NACK)) + err = -EINVAL; + +mbx_err: + return err; +} static void igbvf_set_vfta_all(struct rte_eth_dev *dev, bool on) { @@ -2350,6 +3016,17 @@ igbvf_vlan_filter_set(struct rte_eth_dev *dev, uint16_t vlan_id, int on) return 0; } +static void +igbvf_default_mac_addr_set(struct rte_eth_dev *dev, struct ether_addr *addr) +{ + struct e1000_hw *hw = + E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private); + + /* index is not used by rar_set() */ + hw->mac.ops.rar_set(hw, (void *)addr, 0); +} + + static int eth_igb_rss_reta_update(struct rte_eth_dev *dev, struct rte_eth_rss_reta_entry64 *reta_conf, @@ -3663,6 +4340,462 @@ eth_igb_set_mc_addr_list(struct rte_eth_dev *dev, return 0; } +static uint64_t +igb_read_systime_cyclecounter(struct rte_eth_dev *dev) +{ + struct e1000_hw *hw = E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private); + uint64_t systime_cycles; + + switch (hw->mac.type) { + case e1000_i210: + case e1000_i211: + /* + * Need to read System Time Residue Register to be able + * to read the other two registers. + */ + E1000_READ_REG(hw, E1000_SYSTIMR); + /* SYSTIMEL stores ns and SYSTIMEH stores seconds. */ + systime_cycles = (uint64_t)E1000_READ_REG(hw, E1000_SYSTIML); + systime_cycles += (uint64_t)E1000_READ_REG(hw, E1000_SYSTIMH) + * NSEC_PER_SEC; + break; + case e1000_82580: + case e1000_i350: + case e1000_i354: + /* + * Need to read System Time Residue Register to be able + * to read the other two registers. + */ + E1000_READ_REG(hw, E1000_SYSTIMR); + systime_cycles = (uint64_t)E1000_READ_REG(hw, E1000_SYSTIML); + /* Only the 8 LSB are valid. */ + systime_cycles |= (uint64_t)(E1000_READ_REG(hw, E1000_SYSTIMH) + & 0xff) << 32; + break; + default: + systime_cycles = (uint64_t)E1000_READ_REG(hw, E1000_SYSTIML); + systime_cycles |= (uint64_t)E1000_READ_REG(hw, E1000_SYSTIMH) + << 32; + break; + } + + return systime_cycles; +} + +static uint64_t +igb_read_rx_tstamp_cyclecounter(struct rte_eth_dev *dev) +{ + struct e1000_hw *hw = E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private); + uint64_t rx_tstamp_cycles; + + switch (hw->mac.type) { + case e1000_i210: + case e1000_i211: + /* RXSTMPL stores ns and RXSTMPH stores seconds. */ + rx_tstamp_cycles = (uint64_t)E1000_READ_REG(hw, E1000_RXSTMPL); + rx_tstamp_cycles += (uint64_t)E1000_READ_REG(hw, E1000_RXSTMPH) + * NSEC_PER_SEC; + break; + case e1000_82580: + case e1000_i350: + case e1000_i354: + rx_tstamp_cycles = (uint64_t)E1000_READ_REG(hw, E1000_RXSTMPL); + /* Only the 8 LSB are valid. */ + rx_tstamp_cycles |= (uint64_t)(E1000_READ_REG(hw, E1000_RXSTMPH) + & 0xff) << 32; + break; + default: + rx_tstamp_cycles = (uint64_t)E1000_READ_REG(hw, E1000_RXSTMPL); + rx_tstamp_cycles |= (uint64_t)E1000_READ_REG(hw, E1000_RXSTMPH) + << 32; + break; + } + + return rx_tstamp_cycles; +} + +static uint64_t +igb_read_tx_tstamp_cyclecounter(struct rte_eth_dev *dev) +{ + struct e1000_hw *hw = E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private); + uint64_t tx_tstamp_cycles; + + switch (hw->mac.type) { + case e1000_i210: + case e1000_i211: + /* RXSTMPL stores ns and RXSTMPH stores seconds. */ + tx_tstamp_cycles = (uint64_t)E1000_READ_REG(hw, E1000_TXSTMPL); + tx_tstamp_cycles += (uint64_t)E1000_READ_REG(hw, E1000_TXSTMPH) + * NSEC_PER_SEC; + break; + case e1000_82580: + case e1000_i350: + case e1000_i354: + tx_tstamp_cycles = (uint64_t)E1000_READ_REG(hw, E1000_TXSTMPL); + /* Only the 8 LSB are valid. */ + tx_tstamp_cycles |= (uint64_t)(E1000_READ_REG(hw, E1000_TXSTMPH) + & 0xff) << 32; + break; + default: + tx_tstamp_cycles = (uint64_t)E1000_READ_REG(hw, E1000_TXSTMPL); + tx_tstamp_cycles |= (uint64_t)E1000_READ_REG(hw, E1000_TXSTMPH) + << 32; + break; + } + + return tx_tstamp_cycles; +} + +static void +igb_start_timecounters(struct rte_eth_dev *dev) +{ + struct e1000_hw *hw = E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private); + struct e1000_adapter *adapter = + (struct e1000_adapter *)dev->data->dev_private; + uint32_t incval = 1; + uint32_t shift = 0; + uint64_t mask = E1000_CYCLECOUNTER_MASK; + + switch (hw->mac.type) { + case e1000_82580: + case e1000_i350: + case e1000_i354: + /* 32 LSB bits + 8 MSB bits = 40 bits */ + mask = (1ULL << 40) - 1; + /* fall-through */ + case e1000_i210: + case e1000_i211: + /* + * Start incrementing the register + * used to timestamp PTP packets. + */ + E1000_WRITE_REG(hw, E1000_TIMINCA, incval); + break; + case e1000_82576: + incval = E1000_INCVALUE_82576; + shift = IGB_82576_TSYNC_SHIFT; + E1000_WRITE_REG(hw, E1000_TIMINCA, + E1000_INCPERIOD_82576 | incval); + break; + default: + /* Not supported */ + return; + } + + memset(&adapter->systime_tc, 0, sizeof(struct rte_timecounter)); + memset(&adapter->rx_tstamp_tc, 0, sizeof(struct rte_timecounter)); + memset(&adapter->tx_tstamp_tc, 0, sizeof(struct rte_timecounter)); + + adapter->systime_tc.cc_mask = mask; + adapter->systime_tc.cc_shift = shift; + adapter->systime_tc.nsec_mask = (1ULL << shift) - 1; + + adapter->rx_tstamp_tc.cc_mask = mask; + adapter->rx_tstamp_tc.cc_shift = shift; + adapter->rx_tstamp_tc.nsec_mask = (1ULL << shift) - 1; + + adapter->tx_tstamp_tc.cc_mask = mask; + adapter->tx_tstamp_tc.cc_shift = shift; + adapter->tx_tstamp_tc.nsec_mask = (1ULL << shift) - 1; +} + +static int +igb_timesync_adjust_time(struct rte_eth_dev *dev, int64_t delta) +{ + struct e1000_adapter *adapter = + (struct e1000_adapter *)dev->data->dev_private; + + adapter->systime_tc.nsec += delta; + adapter->rx_tstamp_tc.nsec += delta; + adapter->tx_tstamp_tc.nsec += delta; + + return 0; +} + +static int +igb_timesync_write_time(struct rte_eth_dev *dev, const struct timespec *ts) +{ + uint64_t ns; + struct e1000_adapter *adapter = + (struct e1000_adapter *)dev->data->dev_private; + + ns = rte_timespec_to_ns(ts); + + /* Set the timecounters to a new value. */ + adapter->systime_tc.nsec = ns; + adapter->rx_tstamp_tc.nsec = ns; + adapter->tx_tstamp_tc.nsec = ns; + + return 0; +} + +static int +igb_timesync_read_time(struct rte_eth_dev *dev, struct timespec *ts) +{ + uint64_t ns, systime_cycles; + struct e1000_adapter *adapter = + (struct e1000_adapter *)dev->data->dev_private; + + systime_cycles = igb_read_systime_cyclecounter(dev); + ns = rte_timecounter_update(&adapter->systime_tc, systime_cycles); + *ts = rte_ns_to_timespec(ns); + + return 0; +} + +static int +igb_timesync_enable(struct rte_eth_dev *dev) +{ + struct e1000_hw *hw = E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private); + uint32_t tsync_ctl; + uint32_t tsauxc; + + /* Stop the timesync system time. */ + E1000_WRITE_REG(hw, E1000_TIMINCA, 0x0); + /* Reset the timesync system time value. */ + switch (hw->mac.type) { + case e1000_82580: + case e1000_i350: + case e1000_i354: + case e1000_i210: + case e1000_i211: + E1000_WRITE_REG(hw, E1000_SYSTIMR, 0x0); + /* fall-through */ + case e1000_82576: + E1000_WRITE_REG(hw, E1000_SYSTIML, 0x0); + E1000_WRITE_REG(hw, E1000_SYSTIMH, 0x0); + break; + default: + /* Not supported. */ + return -ENOTSUP; + } + + /* Enable system time for it isn't on by default. */ + tsauxc = E1000_READ_REG(hw, E1000_TSAUXC); + tsauxc &= ~E1000_TSAUXC_DISABLE_SYSTIME; + E1000_WRITE_REG(hw, E1000_TSAUXC, tsauxc); + + igb_start_timecounters(dev); + + /* Enable L2 filtering of IEEE1588/802.1AS Ethernet frame types. */ + E1000_WRITE_REG(hw, E1000_ETQF(E1000_ETQF_FILTER_1588), + (ETHER_TYPE_1588 | + E1000_ETQF_FILTER_ENABLE | + E1000_ETQF_1588)); + + /* Enable timestamping of received PTP packets. */ + tsync_ctl = E1000_READ_REG(hw, E1000_TSYNCRXCTL); + tsync_ctl |= E1000_TSYNCRXCTL_ENABLED; + E1000_WRITE_REG(hw, E1000_TSYNCRXCTL, tsync_ctl); + + /* Enable Timestamping of transmitted PTP packets. */ + tsync_ctl = E1000_READ_REG(hw, E1000_TSYNCTXCTL); + tsync_ctl |= E1000_TSYNCTXCTL_ENABLED; + E1000_WRITE_REG(hw, E1000_TSYNCTXCTL, tsync_ctl); + + return 0; +} + +static int +igb_timesync_disable(struct rte_eth_dev *dev) +{ + struct e1000_hw *hw = E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private); + uint32_t tsync_ctl; + + /* Disable timestamping of transmitted PTP packets. */ + tsync_ctl = E1000_READ_REG(hw, E1000_TSYNCTXCTL); + tsync_ctl &= ~E1000_TSYNCTXCTL_ENABLED; + E1000_WRITE_REG(hw, E1000_TSYNCTXCTL, tsync_ctl); + + /* Disable timestamping of received PTP packets. */ + tsync_ctl = E1000_READ_REG(hw, E1000_TSYNCRXCTL); + tsync_ctl &= ~E1000_TSYNCRXCTL_ENABLED; + E1000_WRITE_REG(hw, E1000_TSYNCRXCTL, tsync_ctl); + + /* Disable L2 filtering of IEEE1588/802.1AS Ethernet frame types. */ + E1000_WRITE_REG(hw, E1000_ETQF(E1000_ETQF_FILTER_1588), 0); + + /* Stop incrementating the System Time registers. */ + E1000_WRITE_REG(hw, E1000_TIMINCA, 0); + + return 0; +} + +static int +igb_timesync_read_rx_timestamp(struct rte_eth_dev *dev, + struct timespec *timestamp, + uint32_t flags __rte_unused) +{ + struct e1000_hw *hw = E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private); + struct e1000_adapter *adapter = + (struct e1000_adapter *)dev->data->dev_private; + uint32_t tsync_rxctl; + uint64_t rx_tstamp_cycles; + uint64_t ns; + + tsync_rxctl = E1000_READ_REG(hw, E1000_TSYNCRXCTL); + if ((tsync_rxctl & E1000_TSYNCRXCTL_VALID) == 0) + return -EINVAL; + + rx_tstamp_cycles = igb_read_rx_tstamp_cyclecounter(dev); + ns = rte_timecounter_update(&adapter->rx_tstamp_tc, rx_tstamp_cycles); + *timestamp = rte_ns_to_timespec(ns); + + return 0; +} + +static int +igb_timesync_read_tx_timestamp(struct rte_eth_dev *dev, + struct timespec *timestamp) +{ + struct e1000_hw *hw = E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private); + struct e1000_adapter *adapter = + (struct e1000_adapter *)dev->data->dev_private; + uint32_t tsync_txctl; + uint64_t tx_tstamp_cycles; + uint64_t ns; + + tsync_txctl = E1000_READ_REG(hw, E1000_TSYNCTXCTL); + if ((tsync_txctl & E1000_TSYNCTXCTL_VALID) == 0) + return -EINVAL; + + tx_tstamp_cycles = igb_read_tx_tstamp_cyclecounter(dev); + ns = rte_timecounter_update(&adapter->tx_tstamp_tc, tx_tstamp_cycles); + *timestamp = rte_ns_to_timespec(ns); + + return 0; +} + +static int +eth_igb_get_reg_length(struct rte_eth_dev *dev __rte_unused) +{ + int count = 0; + int g_ind = 0; + const struct reg_info *reg_group; + + while ((reg_group = igb_regs[g_ind++])) + count += igb_reg_group_count(reg_group); + + return count; +} + +static int +igbvf_get_reg_length(struct rte_eth_dev *dev __rte_unused) +{ + int count = 0; + int g_ind = 0; + const struct reg_info *reg_group; + + while ((reg_group = igbvf_regs[g_ind++])) + count += igb_reg_group_count(reg_group); + + return count; +} + +static int +eth_igb_get_regs(struct rte_eth_dev *dev, + struct rte_dev_reg_info *regs) +{ + struct e1000_hw *hw = E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private); + uint32_t *data = regs->data; + int g_ind = 0; + int count = 0; + const struct reg_info *reg_group; + + /* Support only full register dump */ + if ((regs->length == 0) || + (regs->length == (uint32_t)eth_igb_get_reg_length(dev))) { + regs->version = hw->mac.type << 24 | hw->revision_id << 16 | + hw->device_id; + while ((reg_group = igb_regs[g_ind++])) + count += igb_read_regs_group(dev, &data[count], + reg_group); + return 0; + } + + return -ENOTSUP; +} + +static int +igbvf_get_regs(struct rte_eth_dev *dev, + struct rte_dev_reg_info *regs) +{ + struct e1000_hw *hw = E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private); + uint32_t *data = regs->data; + int g_ind = 0; + int count = 0; + const struct reg_info *reg_group; + + /* Support only full register dump */ + if ((regs->length == 0) || + (regs->length == (uint32_t)igbvf_get_reg_length(dev))) { + regs->version = hw->mac.type << 24 | hw->revision_id << 16 | + hw->device_id; + while ((reg_group = igbvf_regs[g_ind++])) + count += igb_read_regs_group(dev, &data[count], + reg_group); + return 0; + } + + return -ENOTSUP; +} + +static int +eth_igb_get_eeprom_length(struct rte_eth_dev *dev) +{ + struct e1000_hw *hw = E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private); + + /* Return unit is byte count */ + return hw->nvm.word_size * 2; +} + +static int +eth_igb_get_eeprom(struct rte_eth_dev *dev, + struct rte_dev_eeprom_info *in_eeprom) +{ + struct e1000_hw *hw = E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private); + struct e1000_nvm_info *nvm = &hw->nvm; + uint16_t *data = in_eeprom->data; + int first, length; + + first = in_eeprom->offset >> 1; + length = in_eeprom->length >> 1; + if ((first >= hw->nvm.word_size) || + ((first + length) >= hw->nvm.word_size)) + return -EINVAL; + + in_eeprom->magic = hw->vendor_id | + ((uint32_t)hw->device_id << 16); + + if ((nvm->ops.read) == NULL) + return -ENOTSUP; + + return nvm->ops.read(hw, first, length, data); +} + +static int +eth_igb_set_eeprom(struct rte_eth_dev *dev, + struct rte_dev_eeprom_info *in_eeprom) +{ + struct e1000_hw *hw = E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private); + struct e1000_nvm_info *nvm = &hw->nvm; + uint16_t *data = in_eeprom->data; + int first, length; + + first = in_eeprom->offset >> 1; + length = in_eeprom->length >> 1; + if ((first >= hw->nvm.word_size) || + ((first + length) >= hw->nvm.word_size)) + return -EINVAL; + + in_eeprom->magic = (uint32_t)hw->vendor_id | + ((uint32_t)hw->device_id << 16); + + if ((nvm->ops.write) == NULL) + return -ENOTSUP; + return nvm->ops.write(hw, first, length, data); +} + static struct rte_driver pmd_igb_drv = { .type = PMD_PDEV, .init = rte_igb_pmd_init, @@ -3673,5 +4806,166 @@ static struct rte_driver pmd_igbvf_drv = { .init = rte_igbvf_pmd_init, }; +static int +eth_igb_rx_queue_intr_disable(struct rte_eth_dev *dev, uint16_t queue_id) +{ + struct e1000_hw *hw = + E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private); + uint32_t mask = 1 << queue_id; + + E1000_WRITE_REG(hw, E1000_EIMC, mask); + E1000_WRITE_FLUSH(hw); + + return 0; +} + +static int +eth_igb_rx_queue_intr_enable(struct rte_eth_dev *dev, uint16_t queue_id) +{ + struct e1000_hw *hw = + E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private); + uint32_t mask = 1 << queue_id; + uint32_t regval; + + regval = E1000_READ_REG(hw, E1000_EIMS); + E1000_WRITE_REG(hw, E1000_EIMS, regval | mask); + E1000_WRITE_FLUSH(hw); + + rte_intr_enable(&dev->pci_dev->intr_handle); + + return 0; +} + +static void +eth_igb_write_ivar(struct e1000_hw *hw, uint8_t msix_vector, + uint8_t index, uint8_t offset) +{ + uint32_t val = E1000_READ_REG_ARRAY(hw, E1000_IVAR0, index); + + /* clear bits */ + val &= ~((uint32_t)0xFF << offset); + + /* write vector and valid bit */ + val |= (msix_vector | E1000_IVAR_VALID) << offset; + + E1000_WRITE_REG_ARRAY(hw, E1000_IVAR0, index, val); +} + +static void +eth_igb_assign_msix_vector(struct e1000_hw *hw, int8_t direction, + uint8_t queue, uint8_t msix_vector) +{ + uint32_t tmp = 0; + + if (hw->mac.type == e1000_82575) { + if (direction == 0) + tmp = E1000_EICR_RX_QUEUE0 << queue; + else if (direction == 1) + tmp = E1000_EICR_TX_QUEUE0 << queue; + E1000_WRITE_REG(hw, E1000_MSIXBM(msix_vector), tmp); + } else if (hw->mac.type == e1000_82576) { + if ((direction == 0) || (direction == 1)) + eth_igb_write_ivar(hw, msix_vector, queue & 0x7, + ((queue & 0x8) << 1) + + 8 * direction); + } else if ((hw->mac.type == e1000_82580) || + (hw->mac.type == e1000_i350) || + (hw->mac.type == e1000_i354) || + (hw->mac.type == e1000_i210) || + (hw->mac.type == e1000_i211)) { + if ((direction == 0) || (direction == 1)) + eth_igb_write_ivar(hw, msix_vector, + queue >> 1, + ((queue & 0x1) << 4) + + 8 * direction); + } +} + +/* Sets up the hardware to generate MSI-X interrupts properly + * @hw + * board private structure + */ +static void +eth_igb_configure_msix_intr(struct rte_eth_dev *dev) +{ + int queue_id; + uint32_t tmpval, regval, intr_mask; + struct e1000_hw *hw = + E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private); + uint32_t vec = E1000_MISC_VEC_ID; + uint32_t base = E1000_MISC_VEC_ID; + uint32_t misc_shift = 0; + + struct rte_intr_handle *intr_handle = &dev->pci_dev->intr_handle; + + /* won't configure msix register if no mapping is done + * between intr vector and event fd + */ + if (!rte_intr_dp_is_en(intr_handle)) + return; + + if (rte_intr_allow_others(intr_handle)) { + vec = base = E1000_RX_VEC_START; + misc_shift = 1; + } + + /* set interrupt vector for other causes */ + if (hw->mac.type == e1000_82575) { + tmpval = E1000_READ_REG(hw, E1000_CTRL_EXT); + /* enable MSI-X PBA support */ + tmpval |= E1000_CTRL_EXT_PBA_CLR; + + /* Auto-Mask interrupts upon ICR read */ + tmpval |= E1000_CTRL_EXT_EIAME; + tmpval |= E1000_CTRL_EXT_IRCA; + + E1000_WRITE_REG(hw, E1000_CTRL_EXT, tmpval); + + /* enable msix_other interrupt */ + E1000_WRITE_REG_ARRAY(hw, E1000_MSIXBM(0), 0, E1000_EIMS_OTHER); + regval = E1000_READ_REG(hw, E1000_EIAC); + E1000_WRITE_REG(hw, E1000_EIAC, regval | E1000_EIMS_OTHER); + regval = E1000_READ_REG(hw, E1000_EIAM); + E1000_WRITE_REG(hw, E1000_EIMS, regval | E1000_EIMS_OTHER); + } else if ((hw->mac.type == e1000_82576) || + (hw->mac.type == e1000_82580) || + (hw->mac.type == e1000_i350) || + (hw->mac.type == e1000_i354) || + (hw->mac.type == e1000_i210) || + (hw->mac.type == e1000_i211)) { + /* turn on MSI-X capability first */ + E1000_WRITE_REG(hw, E1000_GPIE, E1000_GPIE_MSIX_MODE | + E1000_GPIE_PBA | E1000_GPIE_EIAME | + E1000_GPIE_NSICR); + intr_mask = RTE_LEN2MASK(intr_handle->nb_efd, uint32_t) << + misc_shift; + regval = E1000_READ_REG(hw, E1000_EIAC); + E1000_WRITE_REG(hw, E1000_EIAC, regval | intr_mask); + + /* enable msix_other interrupt */ + regval = E1000_READ_REG(hw, E1000_EIMS); + E1000_WRITE_REG(hw, E1000_EIMS, regval | intr_mask); + tmpval = (dev->data->nb_rx_queues | E1000_IVAR_VALID) << 8; + E1000_WRITE_REG(hw, E1000_IVAR_MISC, tmpval); + } + + /* use EIAM to auto-mask when MSI-X interrupt + * is asserted, this saves a register write for every interrupt + */ + intr_mask = RTE_LEN2MASK(intr_handle->nb_efd, uint32_t) << + misc_shift; + regval = E1000_READ_REG(hw, E1000_EIAM); + E1000_WRITE_REG(hw, E1000_EIAM, regval | intr_mask); + + for (queue_id = 0; queue_id < dev->data->nb_rx_queues; queue_id++) { + eth_igb_assign_msix_vector(hw, 0, queue_id, vec); + intr_handle->intr_vec[queue_id] = vec; + if (vec < base + intr_handle->nb_efd - 1) + vec++; + } + + E1000_WRITE_FLUSH(hw); +} + PMD_REGISTER_DRIVER(pmd_igb_drv); PMD_REGISTER_DRIVER(pmd_igbvf_drv);