add function to support ethtool ops: - set_mac_addr - get_reg_length - get_regs - get_eeprom_length - get_eeprom - set_eeprom
Signed-off-by: Liang-Min Larry Wang <liang-min.wang at intel.com> --- drivers/net/e1000/igb_ethdev.c | 175 ++++++++++++++++++++++++++++++++ drivers/net/e1000/igb_regs.h | 223 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 398 insertions(+) create mode 100644 drivers/net/e1000/igb_regs.h diff --git a/drivers/net/e1000/igb_ethdev.c b/drivers/net/e1000/igb_ethdev.c index eb97218..c6d057f 100644 --- a/drivers/net/e1000/igb_ethdev.c +++ b/drivers/net/e1000/igb_ethdev.c @@ -55,6 +55,7 @@ #include "e1000_logs.h" #include "base/e1000_api.h" #include "e1000_ethdev.h" +#include "igb_regs.h" /* * Default values for port configuration @@ -137,6 +138,8 @@ 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); @@ -150,6 +153,12 @@ 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); @@ -201,6 +210,14 @@ 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, @@ -283,6 +300,7 @@ 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, @@ -293,6 +311,11 @@ static const struct eth_dev_ops eth_igb_ops = { .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, }; /* @@ -314,6 +337,9 @@ static const struct eth_dev_ops igbvf_eth_dev_ops = { .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, + .mac_addr_set = igbvf_default_mac_addr_set, + .get_reg_length = igbvf_get_reg_length, + .get_reg = igbvf_get_regs, }; /** @@ -2133,6 +2159,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 */ @@ -2367,6 +2401,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, @@ -3778,6 +3823,136 @@ igb_timesync_read_tx_timestamp(struct rte_eth_dev *dev, 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 *regs_buff = regs->buf; + int g_ind = 0; + int count = 0; + const struct reg_info *reg_group; + + /* Support only full register dump */ + if ((regs->leng == 0) || + (regs->leng == (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, ®s_buff[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 *regs_buff = regs->buf; + int g_ind = 0; + int count = 0; + const struct reg_info *reg_group; + + /* Support only full register dump */ + if ((regs->leng == 0) || + (regs->leng == (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, ®s_buff[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->buf; + int first, leng; + + first = in_eeprom->offset >> 1; + leng = in_eeprom->leng >> 1; + if ((first >= hw->nvm.word_size) || + ((first + leng) >= 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, leng, 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->buf; + int first, leng; + + first = in_eeprom->offset >> 1; + leng = in_eeprom->leng >> 1; + if ((first >= hw->nvm.word_size) || + ((first + leng) >= 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, leng, data); +} + static struct rte_driver pmd_igb_drv = { .type = PMD_PDEV, .init = rte_igb_pmd_init, diff --git a/drivers/net/e1000/igb_regs.h b/drivers/net/e1000/igb_regs.h new file mode 100644 index 0000000..0b5e5e5 --- /dev/null +++ b/drivers/net/e1000/igb_regs.h @@ -0,0 +1,223 @@ +/*- + * BSD LICENSE + * + * Copyright(c) 2015 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 + * are met: + * + * * 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 + * distribution. + * * 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 + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef _IGB_REGS_H_ +#define _IGB_REGS_H_ + +#include "e1000_ethdev.h" + +struct reg_info { + uint32_t base_addr; + uint32_t count; + uint32_t stride; + const char *name; +}; + +static const struct reg_info igb_regs_general[] = { + {E1000_CTRL, 1, 1, "E1000_CTRL"}, + {E1000_STATUS, 1, 1, "E1000_STATUS"}, + {E1000_CTRL_EXT, 1, 1, "E1000_CTRL_EXT"}, + {E1000_MDIC, 1, 1, "E1000_MDIC"}, + {E1000_SCTL, 1, 1, "E1000_SCTL"}, + {E1000_CONNSW, 1, 1, "E1000_CONNSW"}, + {E1000_VET, 1, 1, "E1000_VET"}, + {E1000_LEDCTL, 1, 1, "E1000_LEDCTL"}, + {E1000_PBA, 1, 1, "E1000_PBA"}, + {E1000_PBS, 1, 1, "E1000_PBS"}, + {E1000_FRTIMER, 1, 1, "E1000_FRTIMER"}, + {E1000_TCPTIMER, 1, 1, "E1000_TCPTIMER"}, + {0, 0, 0, ""} +}; + +static const struct reg_info igb_regs_nvm[] = { + {E1000_EECD, 1, 1, "E1000_EECD"}, + {0, 0, 0, ""} +}; + +static const struct reg_info igb_regs_interrupt[] = { + {E1000_EICS, 1, 1, "E1000_EICS"}, + {E1000_EIMS, 1, 1, "E1000_EIMS"}, + {E1000_EIMC, 1, 1, "E1000_EIMC"}, + {E1000_EIAC, 1, 1, "E1000_EIAC"}, + {E1000_EIAM, 1, 1, "E1000_EIAM"}, + {E1000_ICS, 1, 1, "E1000_ICS"}, + {E1000_IMS, 1, 1, "E1000_IMS"}, + {E1000_IMC, 1, 1, "E1000_IMC"}, + {E1000_IAC, 1, 1, "E1000_IAC"}, + {E1000_IAM, 1, 1, "E1000_IAM"}, + {E1000_IMIRVP, 1, 1, "E1000_IMIRVP"}, + {E1000_EITR(0), 10, 4, "E1000_EITR"}, + {E1000_IMIR(0), 8, 4, "E1000_IMIR"}, + {E1000_IMIREXT(0), 8, 4, "E1000_IMIREXT"}, + {0, 0, 0, ""} +}; + +static const struct reg_info igb_regs_fctl[] = { + {E1000_FCAL, 1, 1, "E1000_FCAL"}, + {E1000_FCAH, 1, 1, "E1000_FCAH"}, + {E1000_FCTTV, 1, 1, "E1000_FCTTV"}, + {E1000_FCRTL, 1, 1, "E1000_FCRTL"}, + {E1000_FCRTH, 1, 1, "E1000_FCRTH"}, + {E1000_FCRTV, 1, 1, "E1000_FCRTV"}, + {0, 0, 0, ""} +}; + +static const struct reg_info igb_regs_rxdma[] = { + {E1000_RDBAL(0), 4, 0x100, "E1000_RDBAL"}, + {E1000_RDBAH(0), 4, 0x100, "E1000_RDBAH"}, + {E1000_RDLEN(0), 4, 0x100, "E1000_RDLEN"}, + {E1000_RDH(0), 4, 0x100, "E1000_RDH"}, + {E1000_RDT(0), 4, 0x100, "E1000_RDT"}, + {E1000_RXCTL(0), 4, 0x100, "E1000_RXCTL"}, + {E1000_SRRCTL(0), 4, 0x100, "E1000_SRRCTL"}, + {E1000_DCA_RXCTRL(0), 4, 0x100, "E1000_DCA_RXCTRL"}, + {0, 0, 0, ""} +}; + +static const struct reg_info igb_regs_rx[] = { + {E1000_RCTL, 1, 1, "E1000_RCTL"}, + {E1000_RXCSUM, 1, 1, "E1000_RXCSUM"}, + {E1000_RLPML, 1, 1, "E1000_RLPML"}, + {E1000_RFCTL, 1, 1, "E1000_RFCTL"}, + {E1000_MRQC, 1, 1, "E1000_MRQC"}, + {E1000_VT_CTL, 1, 1, "E1000_VT_CTL"}, + {E1000_RAL(0), 16, 8, "E1000_RAL"}, + {E1000_RAH(0), 16, 8, "E1000_RAH"}, + {0, 0, 0, ""} +}; + +static const struct reg_info igb_regs_tx[] = { + {E1000_TCTL, 1, 1, "E1000_TCTL"}, + {E1000_TCTL_EXT, 1, 1, "E1000_TCTL_EXT"}, + {E1000_TIPG, 1, 1, "E1000_TIPG"}, + {E1000_DTXCTL, 1, 1, "E1000_DTXCTL"}, + {E1000_TDBAL(0), 4, 0x100, "E1000_TDBAL"}, + {E1000_TDBAH(0), 4, 0x100, "E1000_TDBAH"}, + {E1000_TDLEN(0), 4, 0x100, "E1000_TDLEN"}, + {E1000_TDH(0), 4, 0x100, "E1000_TDLEN"}, + {E1000_TDT(0), 4, 0x100, "E1000_TDT"}, + {E1000_TXDCTL(0), 4, 0x100, "E1000_TXDCTL"}, + {E1000_TDWBAL(0), 4, 0x100, "E1000_TDWBAL"}, + {E1000_TDWBAH(0), 4, 0x100, "E1000_TDWBAH"}, + {E1000_DCA_TXCTRL(0), 4, 0x100, "E1000_DCA_TXCTRL"}, + {E1000_TDFH, 1, 1, "E1000_TDFH"}, + {E1000_TDFT, 1, 1, "E1000_TDFT"}, + {E1000_TDFHS, 1, 1, "E1000_TDFHS"}, + {E1000_TDFPC, 1, 1, "E1000_TDFPC"}, + {0, 0, 0, ""} +}; + +static const struct reg_info igb_regs_wakeup[] = { + {E1000_WUC, 1, 1, "E1000_WUC"}, + {E1000_WUFC, 1, 1, "E1000_WUFC"}, + {E1000_WUS, 1, 1, "E1000_WUS"}, + {E1000_IPAV, 1, 1, "E1000_IPAV"}, + {E1000_WUPL, 1, 1, "E1000_WUPL"}, + {E1000_IP4AT_REG(0), 4, 8, "E1000_IP4AT_REG"}, + {E1000_IP6AT_REG(0), 4, 4, "E1000_IP6AT_REG"}, + {E1000_WUPM_REG(0), 4, 4, "E1000_WUPM_REG"}, + {E1000_FFMT_REG(0), 4, 8, "E1000_FFMT_REG"}, + {E1000_FFVT_REG(0), 4, 8, "E1000_FFVT_REG"}, + {E1000_FFLT_REG(0), 4, 8, "E1000_FFLT_REG"}, + {0, 0, 0, ""} +}; + +static const struct reg_info igb_regs_mac[] = { + {E1000_PCS_CFG0, 1, 1, "E1000_PCS_CFG0"}, + {E1000_PCS_LCTL, 1, 1, "E1000_PCS_LCTL"}, + {E1000_PCS_LSTAT, 1, 1, "E1000_PCS_LSTAT"}, + {E1000_PCS_ANADV, 1, 1, "E1000_PCS_ANADV"}, + {E1000_PCS_LPAB, 1, 1, "E1000_PCS_LPAB"}, + {E1000_PCS_NPTX, 1, 1, "E1000_PCS_NPTX"}, + {E1000_PCS_LPABNP, 1, 1, "E1000_PCS_LPABNP"}, + {0, 0, 0, ""} +}; + +static const struct reg_info *igb_regs[] = { + igb_regs_general, + igb_regs_nvm, + igb_regs_interrupt, + igb_regs_fctl, + igb_regs_rxdma, + igb_regs_rx, + igb_regs_tx, + igb_regs_wakeup, + igb_regs_mac, + NULL}; + +/* FIXME: reading igb_regs_interrupt results side-effect which doesn't + * work with VFIO; re-install igb_regs_interrupt once issue is resolved. + */ +static const struct reg_info *igbvf_regs[] = { + igb_regs_general, + igb_regs_rxdma, + igb_regs_tx, + NULL}; + +static inline int +igb_read_regs(struct e1000_hw *hw, const struct reg_info *reg, + uint32_t *reg_buf) +{ + unsigned int i; + + for (i = 0; i < reg->count; i++) { + reg_buf[i] = E1000_READ_REG(hw, + reg->base_addr + i * reg->stride); + } + return reg->count; +}; + +static inline int +igb_reg_group_count(const struct reg_info *regs) +{ + int count = 0; + int i = 0; + + while (regs[i].count) + count += regs[i++].count; + return count; +}; + +static inline int +igb_read_regs_group(struct rte_eth_dev *dev, uint32_t *reg_buf, + const struct reg_info *regs) +{ + int count = 0; + int i = 0; + struct e1000_hw *hw = E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private); + + while (regs[i].count) + count += igb_read_regs(hw, ®s[i++], ®_buf[count]); + return count; +}; + +#endif /* _IGB_REGS_H_ */ -- 2.1.4