ixgbe: add access to specific device info
[dpdk.git] / drivers / net / ixgbe / ixgbe_ethdev.c
index b7a60b1..f143fb1 100644 (file)
@@ -68,6 +68,9 @@
 #include "ixgbe_ethdev.h"
 #include "ixgbe_bypass.h"
 #include "ixgbe_rxtx.h"
+#include "base/ixgbe_type.h"
+#include "base/ixgbe_phy.h"
+#include "ixgbe_regs.h"
 
 /*
  * High threshold controlling when to start sending XOFF frames. Must be at
@@ -91,6 +94,7 @@
 
 #define IXGBE_MMW_SIZE_DEFAULT        0x4
 #define IXGBE_MMW_SIZE_JUMBO_FRAME    0x14
+#define IXGBE_MAX_RING_DESC           4096 /* replicate define from rxtx */
 
 /*
  *  Default values for RX/TX configuration
 
 #define IXGBE_HKEY_MAX_INDEX 10
 
+/* Additional timesync values. */
+#define IXGBE_TIMINCA_16NS_SHIFT 24
+#define IXGBE_TIMINCA_INCVALUE   16000000
+#define IXGBE_TIMINCA_INIT       ((0x02 << IXGBE_TIMINCA_16NS_SHIFT) \
+                                 | IXGBE_TIMINCA_INCVALUE)
+
 static int eth_ixgbe_dev_init(struct rte_eth_dev *eth_dev);
 static int  ixgbe_dev_configure(struct rte_eth_dev *dev);
 static int  ixgbe_dev_start(struct rte_eth_dev *dev);
@@ -181,6 +191,8 @@ 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);
 static void ixgbe_remove_rar(struct rte_eth_dev *dev, uint32_t index);
+static void ixgbe_set_default_mac_addr(struct rte_eth_dev *dev,
+                                          struct ether_addr *mac_addr);
 static void ixgbe_dcb_init(struct ixgbe_hw *hw,struct ixgbe_dcb_config *dcb_config);
 
 /* For Virtual Function support */
@@ -225,6 +237,8 @@ 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);
+static void ixgbevf_set_default_mac_addr(struct rte_eth_dev *dev,
+                                            struct ether_addr *mac_addr);
 static int ixgbe_syn_filter_set(struct rte_eth_dev *dev,
                        struct rte_eth_syn_filter *filter,
                        bool add);
@@ -263,6 +277,27 @@ static int ixgbe_dev_set_mc_addr_list(struct rte_eth_dev *dev,
                                      struct ether_addr *mc_addr_set,
                                      uint32_t nb_mc_addr);
 
+static int ixgbe_get_reg_length(struct rte_eth_dev *dev);
+static int ixgbe_get_regs(struct rte_eth_dev *dev,
+                           struct rte_dev_reg_info *regs);
+static int ixgbe_get_eeprom_length(struct rte_eth_dev *dev);
+static int ixgbe_get_eeprom(struct rte_eth_dev *dev,
+                               struct rte_dev_eeprom_info *eeprom);
+static int ixgbe_set_eeprom(struct rte_eth_dev *dev,
+                               struct rte_dev_eeprom_info *eeprom);
+
+static int ixgbevf_get_reg_length(struct rte_eth_dev *dev);
+static int ixgbevf_get_regs(struct rte_eth_dev *dev,
+                               struct rte_dev_reg_info *regs);
+
+static int ixgbe_timesync_enable(struct rte_eth_dev *dev);
+static int ixgbe_timesync_disable(struct rte_eth_dev *dev);
+static int ixgbe_timesync_read_rx_timestamp(struct rte_eth_dev *dev,
+                                           struct timespec *timestamp,
+                                           uint32_t flags);
+static int ixgbe_timesync_read_tx_timestamp(struct rte_eth_dev *dev,
+                                           struct timespec *timestamp);
+
 /*
  * Define VF Stats MACRO for Non "cleared on read" register
  */
@@ -361,6 +396,7 @@ static const struct eth_dev_ops ixgbe_eth_dev_ops = {
        .priority_flow_ctrl_set = ixgbe_priority_flow_ctrl_set,
        .mac_addr_add         = ixgbe_add_rar,
        .mac_addr_remove      = ixgbe_remove_rar,
+       .mac_addr_set         = ixgbe_set_default_mac_addr,
        .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,
@@ -388,6 +424,15 @@ static const struct eth_dev_ops ixgbe_eth_dev_ops = {
        .rss_hash_conf_get    = ixgbe_dev_rss_hash_conf_get,
        .filter_ctrl          = ixgbe_dev_filter_ctrl,
        .set_mc_addr_list     = ixgbe_dev_set_mc_addr_list,
+       .timesync_enable      = ixgbe_timesync_enable,
+       .timesync_disable     = ixgbe_timesync_disable,
+       .timesync_read_rx_timestamp = ixgbe_timesync_read_rx_timestamp,
+       .timesync_read_tx_timestamp = ixgbe_timesync_read_tx_timestamp,
+       .get_reg_length       = ixgbe_get_reg_length,
+       .get_reg              = ixgbe_get_regs,
+       .get_eeprom_length    = ixgbe_get_eeprom_length,
+       .get_eeprom           = ixgbe_get_eeprom,
+       .set_eeprom           = ixgbe_set_eeprom,
 };
 
 /*
@@ -414,6 +459,9 @@ static const struct eth_dev_ops ixgbevf_eth_dev_ops = {
        .mac_addr_add         = ixgbevf_add_mac_addr,
        .mac_addr_remove      = ixgbevf_remove_mac_addr,
        .set_mc_addr_list     = ixgbe_dev_set_mc_addr_list,
+       .mac_addr_set         = ixgbevf_set_default_mac_addr,
+       .get_reg_length       = ixgbevf_get_reg_length,
+       .get_reg              = ixgbevf_get_regs,
 };
 
 /**
@@ -848,6 +896,9 @@ eth_ixgbe_dev_init(struct rte_eth_dev *eth_dev)
                return -EIO;
        }
 
+       /* Reset the hw statistics */
+       ixgbe_dev_stats_reset(eth_dev);
+
        /* disable interrupt */
        ixgbe_disable_intr(hw);
 
@@ -1020,6 +1071,9 @@ eth_ixgbevf_dev_init(struct rte_eth_dev *eth_dev)
        /* init_mailbox_params */
        hw->mbx.ops.init_params(hw);
 
+       /* Reset the hw statistics */
+       ixgbevf_dev_stats_reset(eth_dev);
+
        /* Disable the interrupts for VF */
        ixgbevf_intr_disable(hw);
 
@@ -2552,8 +2606,6 @@ ixgbe_flow_ctrl_set(struct rte_eth_dev *dev, struct rte_eth_fc_conf *fc_conf)
        PMD_INIT_FUNC_TRACE();
 
        hw = IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private);
-       if (fc_conf->autoneg != !hw->fc.disable_fc_autoneg)
-               return -ENOTSUP;
        rx_buf_size = IXGBE_READ_REG(hw, IXGBE_RXPBSIZE(0));
        PMD_INIT_LOG(DEBUG, "Rx packet buffer size = 0x%x", rx_buf_size);
 
@@ -2574,6 +2626,7 @@ ixgbe_flow_ctrl_set(struct rte_eth_dev *dev, struct rte_eth_fc_conf *fc_conf)
        hw->fc.high_water[0]  = fc_conf->high_water;
        hw->fc.low_water[0]   = fc_conf->low_water;
        hw->fc.send_xon       = fc_conf->send_xon;
+       hw->fc.disable_fc_autoneg = !fc_conf->autoneg;
 
        err = ixgbe_fc_enable(hw);
 
@@ -2905,6 +2958,14 @@ ixgbe_remove_rar(struct rte_eth_dev *dev, uint32_t index)
        ixgbe_clear_rar(hw, index);
 }
 
+static void
+ixgbe_set_default_mac_addr(struct rte_eth_dev *dev, struct ether_addr *addr)
+{
+       ixgbe_remove_rar(dev, 0);
+
+       ixgbe_add_rar(dev, addr, 0, 0);
+}
+
 static int
 ixgbe_dev_mtu_set(struct rte_eth_dev *dev, uint16_t mtu)
 {
@@ -3762,6 +3823,14 @@ ixgbevf_remove_mac_addr(struct rte_eth_dev *dev, uint32_t index)
        }
 }
 
+static void
+ixgbevf_set_default_mac_addr(struct rte_eth_dev *dev, struct ether_addr *addr)
+{
+       struct ixgbe_hw *hw = IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+
+       hw->mac.ops.set_rar(hw, 0, (void *)addr, 0, 0);
+}
+
 #define MAC_TYPE_FILTER_SUP(type)    do {\
        if ((type) != ixgbe_mac_82599EB && (type) != ixgbe_mac_X540 &&\
                (type) != ixgbe_mac_X550)\
@@ -4502,8 +4571,8 @@ ixgbe_dev_addr_list_itr(__attribute__((unused)) struct ixgbe_hw *hw,
 
 static int
 ixgbe_dev_set_mc_addr_list(struct rte_eth_dev *dev,
-                          struct ether_addr *mc_addr_set,
-                          uint32_t nb_mc_addr)
+                         struct ether_addr *mc_addr_set,
+                         uint32_t nb_mc_addr)
 {
        struct ixgbe_hw *hw;
        u8 *mc_addr_list;
@@ -4514,6 +4583,238 @@ ixgbe_dev_set_mc_addr_list(struct rte_eth_dev *dev,
                                         ixgbe_dev_addr_list_itr, TRUE);
 }
 
+static int
+ixgbe_timesync_enable(struct rte_eth_dev *dev)
+{
+       struct ixgbe_hw *hw = IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+       uint32_t tsync_ctl;
+       uint32_t tsauxc;
+
+       /* Enable system time for platforms where it isn't on by default. */
+       tsauxc = IXGBE_READ_REG(hw, IXGBE_TSAUXC);
+       tsauxc &= ~IXGBE_TSAUXC_DISABLE_SYSTIME;
+       IXGBE_WRITE_REG(hw, IXGBE_TSAUXC, tsauxc);
+
+       /* Start incrementing the register used to timestamp PTP packets. */
+       IXGBE_WRITE_REG(hw, IXGBE_TIMINCA, IXGBE_TIMINCA_INIT);
+
+       /* Enable L2 filtering of IEEE1588/802.1AS Ethernet frame types. */
+       IXGBE_WRITE_REG(hw, IXGBE_ETQF(IXGBE_ETQF_FILTER_1588),
+                       (ETHER_TYPE_1588 |
+                        IXGBE_ETQF_FILTER_EN |
+                        IXGBE_ETQF_1588));
+
+       /* Enable timestamping of received PTP packets. */
+       tsync_ctl = IXGBE_READ_REG(hw, IXGBE_TSYNCRXCTL);
+       tsync_ctl |= IXGBE_TSYNCRXCTL_ENABLED;
+       IXGBE_WRITE_REG(hw, IXGBE_TSYNCRXCTL, tsync_ctl);
+
+       /* Enable timestamping of transmitted PTP packets. */
+       tsync_ctl = IXGBE_READ_REG(hw, IXGBE_TSYNCTXCTL);
+       tsync_ctl |= IXGBE_TSYNCTXCTL_ENABLED;
+       IXGBE_WRITE_REG(hw, IXGBE_TSYNCTXCTL, tsync_ctl);
+
+       return 0;
+}
+
+static int
+ixgbe_timesync_disable(struct rte_eth_dev *dev)
+{
+       struct ixgbe_hw *hw = IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+       uint32_t tsync_ctl;
+
+       /* Disable timestamping of transmitted PTP packets. */
+       tsync_ctl = IXGBE_READ_REG(hw, IXGBE_TSYNCTXCTL);
+       tsync_ctl &= ~IXGBE_TSYNCTXCTL_ENABLED;
+       IXGBE_WRITE_REG(hw, IXGBE_TSYNCTXCTL, tsync_ctl);
+
+       /* Disable timestamping of received PTP packets. */
+       tsync_ctl = IXGBE_READ_REG(hw, IXGBE_TSYNCRXCTL);
+       tsync_ctl &= ~IXGBE_TSYNCRXCTL_ENABLED;
+       IXGBE_WRITE_REG(hw, IXGBE_TSYNCRXCTL, tsync_ctl);
+
+       /* Disable L2 filtering of IEEE1588/802.1AS Ethernet frame types. */
+       IXGBE_WRITE_REG(hw, IXGBE_ETQF(IXGBE_ETQF_FILTER_1588), 0);
+
+       /* Stop incrementating the System Time registers. */
+       IXGBE_WRITE_REG(hw, IXGBE_TIMINCA, 0);
+
+       return 0;
+}
+
+static int
+ixgbe_timesync_read_rx_timestamp(struct rte_eth_dev *dev,
+                                struct timespec *timestamp,
+                                uint32_t flags __rte_unused)
+{
+       struct ixgbe_hw *hw = IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+       uint32_t tsync_rxctl;
+       uint32_t rx_stmpl;
+       uint32_t rx_stmph;
+
+       tsync_rxctl = IXGBE_READ_REG(hw, IXGBE_TSYNCRXCTL);
+       if ((tsync_rxctl & IXGBE_TSYNCRXCTL_VALID) == 0)
+               return -EINVAL;
+
+       rx_stmpl = IXGBE_READ_REG(hw, IXGBE_RXSTMPL);
+       rx_stmph = IXGBE_READ_REG(hw, IXGBE_RXSTMPH);
+
+       timestamp->tv_sec = (uint64_t)(((uint64_t)rx_stmph << 32) | rx_stmpl);
+       timestamp->tv_nsec = 0;
+
+       return  0;
+}
+
+static int
+ixgbe_timesync_read_tx_timestamp(struct rte_eth_dev *dev,
+                                struct timespec *timestamp)
+{
+       struct ixgbe_hw *hw = IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+       uint32_t tsync_txctl;
+       uint32_t tx_stmpl;
+       uint32_t tx_stmph;
+
+       tsync_txctl = IXGBE_READ_REG(hw, IXGBE_TSYNCTXCTL);
+       if ((tsync_txctl & IXGBE_TSYNCTXCTL_VALID) == 0)
+               return -EINVAL;
+
+       tx_stmpl = IXGBE_READ_REG(hw, IXGBE_TXSTMPL);
+       tx_stmph = IXGBE_READ_REG(hw, IXGBE_TXSTMPH);
+
+       timestamp->tv_sec = (uint64_t)(((uint64_t)tx_stmph << 32) | tx_stmpl);
+       timestamp->tv_nsec = 0;
+
+       return  0;
+}
+
+static int
+ixgbe_get_reg_length(struct rte_eth_dev *dev)
+{
+       struct ixgbe_hw *hw = IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+       int count = 0;
+       int g_ind = 0;
+       const struct reg_info *reg_group;
+       const struct reg_info **reg_set = (hw->mac.type == ixgbe_mac_82598EB) ?
+                                   ixgbe_regs_mac_82598EB : ixgbe_regs_others;
+
+       while ((reg_group = reg_set[g_ind++]))
+               count += ixgbe_regs_group_count(reg_group);
+
+       return count;
+}
+
+static int
+ixgbevf_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 = ixgbevf_regs[g_ind++]))
+               count += ixgbe_regs_group_count(reg_group);
+
+       return count;
+}
+
+static int
+ixgbe_get_regs(struct rte_eth_dev *dev,
+             struct rte_dev_reg_info *regs)
+{
+       struct ixgbe_hw *hw = IXGBE_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;
+       const struct reg_info **reg_set = (hw->mac.type == ixgbe_mac_82598EB) ?
+                                   ixgbe_regs_mac_82598EB : ixgbe_regs_others;
+
+       /* Support only full register dump */
+       if ((regs->length == 0) ||
+           (regs->length == (uint32_t)ixgbe_get_reg_length(dev))) {
+               regs->version = hw->mac.type << 24 | hw->revision_id << 16 |
+                       hw->device_id;
+               while ((reg_group = reg_set[g_ind++]))
+                       count += ixgbe_read_regs_group(dev, &data[count],
+                               reg_group);
+               return 0;
+       }
+
+       return -ENOTSUP;
+}
+
+static int
+ixgbevf_get_regs(struct rte_eth_dev *dev,
+               struct rte_dev_reg_info *regs)
+{
+       struct ixgbe_hw *hw = IXGBE_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)ixgbevf_get_reg_length(dev))) {
+               regs->version = hw->mac.type << 24 | hw->revision_id << 16 |
+                       hw->device_id;
+               while ((reg_group = ixgbevf_regs[g_ind++]))
+                       count += ixgbe_read_regs_group(dev, &data[count],
+                                                     reg_group);
+               return 0;
+       }
+
+       return -ENOTSUP;
+}
+
+static int
+ixgbe_get_eeprom_length(struct rte_eth_dev *dev)
+{
+       struct ixgbe_hw *hw = IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+
+       /* Return unit is byte count */
+       return hw->eeprom.word_size * 2;
+}
+
+static int
+ixgbe_get_eeprom(struct rte_eth_dev *dev,
+               struct rte_dev_eeprom_info *in_eeprom)
+{
+       struct ixgbe_hw *hw = IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+       struct ixgbe_eeprom_info *eeprom = &hw->eeprom;
+       uint16_t *data = in_eeprom->data;
+       int first, length;
+
+       first = in_eeprom->offset >> 1;
+       length = in_eeprom->length >> 1;
+       if ((first >= hw->eeprom.word_size) ||
+           ((first + length) >= hw->eeprom.word_size))
+               return -EINVAL;
+
+       in_eeprom->magic = hw->vendor_id | (hw->device_id << 16);
+
+       return eeprom->ops.read_buffer(hw, first, length, data);
+}
+
+static int
+ixgbe_set_eeprom(struct rte_eth_dev *dev,
+               struct rte_dev_eeprom_info *in_eeprom)
+{
+       struct ixgbe_hw *hw = IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+       struct ixgbe_eeprom_info *eeprom = &hw->eeprom;
+       uint16_t *data = in_eeprom->data;
+       int first, length;
+
+       first = in_eeprom->offset >> 1;
+       length = in_eeprom->length >> 1;
+       if ((first >= hw->eeprom.word_size) ||
+           ((first + length) >= hw->eeprom.word_size))
+               return -EINVAL;
+
+       in_eeprom->magic = hw->vendor_id | (hw->device_id << 16);
+
+       return eeprom->ops.write_buffer(hw,  first, length, data);
+}
+
 static struct rte_driver rte_ixgbe_driver = {
        .type = PMD_PDEV,
        .init = rte_ixgbe_pmd_init,