+static int
+ngbe_dev_led_on(struct rte_eth_dev *dev)
+{
+ struct ngbe_hw *hw = ngbe_dev_hw(dev);
+ return hw->mac.led_on(hw, 0) == 0 ? 0 : -ENOTSUP;
+}
+
+static int
+ngbe_dev_led_off(struct rte_eth_dev *dev)
+{
+ struct ngbe_hw *hw = ngbe_dev_hw(dev);
+ return hw->mac.led_off(hw, 0) == 0 ? 0 : -ENOTSUP;
+}
+
+static int
+ngbe_flow_ctrl_get(struct rte_eth_dev *dev, struct rte_eth_fc_conf *fc_conf)
+{
+ struct ngbe_hw *hw = ngbe_dev_hw(dev);
+ uint32_t mflcn_reg;
+ uint32_t fccfg_reg;
+ int rx_pause;
+ int tx_pause;
+
+ fc_conf->pause_time = hw->fc.pause_time;
+ fc_conf->high_water = hw->fc.high_water;
+ fc_conf->low_water = hw->fc.low_water;
+ fc_conf->send_xon = hw->fc.send_xon;
+ fc_conf->autoneg = !hw->fc.disable_fc_autoneg;
+
+ /*
+ * Return rx_pause status according to actual setting of
+ * RXFCCFG register.
+ */
+ mflcn_reg = rd32(hw, NGBE_RXFCCFG);
+ if (mflcn_reg & NGBE_RXFCCFG_FC)
+ rx_pause = 1;
+ else
+ rx_pause = 0;
+
+ /*
+ * Return tx_pause status according to actual setting of
+ * TXFCCFG register.
+ */
+ fccfg_reg = rd32(hw, NGBE_TXFCCFG);
+ if (fccfg_reg & NGBE_TXFCCFG_FC)
+ tx_pause = 1;
+ else
+ tx_pause = 0;
+
+ if (rx_pause && tx_pause)
+ fc_conf->mode = RTE_ETH_FC_FULL;
+ else if (rx_pause)
+ fc_conf->mode = RTE_ETH_FC_RX_PAUSE;
+ else if (tx_pause)
+ fc_conf->mode = RTE_ETH_FC_TX_PAUSE;
+ else
+ fc_conf->mode = RTE_ETH_FC_NONE;
+
+ return 0;
+}
+
+static int
+ngbe_flow_ctrl_set(struct rte_eth_dev *dev, struct rte_eth_fc_conf *fc_conf)
+{
+ struct ngbe_hw *hw = ngbe_dev_hw(dev);
+ int err;
+ uint32_t rx_buf_size;
+ uint32_t max_high_water;
+ enum ngbe_fc_mode rte_fcmode_2_ngbe_fcmode[] = {
+ ngbe_fc_none,
+ ngbe_fc_rx_pause,
+ ngbe_fc_tx_pause,
+ ngbe_fc_full
+ };
+
+ PMD_INIT_FUNC_TRACE();
+
+ rx_buf_size = rd32(hw, NGBE_PBRXSIZE);
+ PMD_INIT_LOG(DEBUG, "Rx packet buffer size = 0x%x", rx_buf_size);
+
+ /*
+ * At least reserve one Ethernet frame for watermark
+ * high_water/low_water in kilo bytes for ngbe
+ */
+ max_high_water = (rx_buf_size - RTE_ETHER_MAX_LEN) >> 10;
+ if (fc_conf->high_water > max_high_water ||
+ fc_conf->high_water < fc_conf->low_water) {
+ PMD_INIT_LOG(ERR, "Invalid high/low water setup value in KB");
+ PMD_INIT_LOG(ERR, "High_water must <= 0x%x", max_high_water);
+ return -EINVAL;
+ }
+
+ hw->fc.requested_mode = rte_fcmode_2_ngbe_fcmode[fc_conf->mode];
+ hw->fc.pause_time = fc_conf->pause_time;
+ hw->fc.high_water = fc_conf->high_water;
+ hw->fc.low_water = fc_conf->low_water;
+ hw->fc.send_xon = fc_conf->send_xon;
+ hw->fc.disable_fc_autoneg = !fc_conf->autoneg;
+
+ err = hw->mac.fc_enable(hw);
+
+ /* Not negotiated is not an error case */
+ if (err == 0 || err == NGBE_ERR_FC_NOT_NEGOTIATED) {
+ wr32m(hw, NGBE_MACRXFLT, NGBE_MACRXFLT_CTL_MASK,
+ (fc_conf->mac_ctrl_frame_fwd
+ ? NGBE_MACRXFLT_CTL_NOPS : NGBE_MACRXFLT_CTL_DROP));
+ ngbe_flush(hw);
+
+ return 0;
+ }
+
+ PMD_INIT_LOG(ERR, "ngbe_fc_enable = 0x%x", err);
+ return -EIO;
+}
+
+int
+ngbe_dev_rss_reta_update(struct rte_eth_dev *dev,
+ struct rte_eth_rss_reta_entry64 *reta_conf,
+ uint16_t reta_size)
+{
+ uint8_t i, j, mask;
+ uint32_t reta;
+ uint16_t idx, shift;
+ struct ngbe_adapter *adapter = ngbe_dev_adapter(dev);
+ struct ngbe_hw *hw = ngbe_dev_hw(dev);
+
+ PMD_INIT_FUNC_TRACE();
+
+ if (!hw->is_pf) {
+ PMD_DRV_LOG(ERR, "RSS reta update is not supported on this "
+ "NIC.");
+ return -ENOTSUP;
+ }
+
+ if (reta_size != RTE_ETH_RSS_RETA_SIZE_128) {
+ PMD_DRV_LOG(ERR, "The size of hash lookup table configured "
+ "(%d) doesn't match the number hardware can supported "
+ "(%d)", reta_size, RTE_ETH_RSS_RETA_SIZE_128);
+ return -EINVAL;
+ }
+
+ for (i = 0; i < reta_size; i += 4) {
+ idx = i / RTE_ETH_RETA_GROUP_SIZE;
+ shift = i % RTE_ETH_RETA_GROUP_SIZE;
+ mask = (uint8_t)RS64(reta_conf[idx].mask, shift, 0xF);
+ if (!mask)
+ continue;
+
+ reta = rd32a(hw, NGBE_REG_RSSTBL, i >> 2);
+ for (j = 0; j < 4; j++) {
+ if (RS8(mask, j, 0x1)) {
+ reta &= ~(MS32(8 * j, 0xFF));
+ reta |= LS32(reta_conf[idx].reta[shift + j],
+ 8 * j, 0xFF);
+ }
+ }
+ wr32a(hw, NGBE_REG_RSSTBL, i >> 2, reta);
+ }
+ adapter->rss_reta_updated = 1;
+
+ return 0;
+}
+
+int
+ngbe_dev_rss_reta_query(struct rte_eth_dev *dev,
+ struct rte_eth_rss_reta_entry64 *reta_conf,
+ uint16_t reta_size)
+{
+ struct ngbe_hw *hw = ngbe_dev_hw(dev);
+ uint8_t i, j, mask;
+ uint32_t reta;
+ uint16_t idx, shift;
+
+ PMD_INIT_FUNC_TRACE();
+
+ if (reta_size != RTE_ETH_RSS_RETA_SIZE_128) {
+ PMD_DRV_LOG(ERR, "The size of hash lookup table configured "
+ "(%d) doesn't match the number hardware can supported "
+ "(%d)", reta_size, RTE_ETH_RSS_RETA_SIZE_128);
+ return -EINVAL;
+ }
+
+ for (i = 0; i < reta_size; i += 4) {
+ idx = i / RTE_ETH_RETA_GROUP_SIZE;
+ shift = i % RTE_ETH_RETA_GROUP_SIZE;
+ mask = (uint8_t)RS64(reta_conf[idx].mask, shift, 0xF);
+ if (!mask)
+ continue;
+
+ reta = rd32a(hw, NGBE_REG_RSSTBL, i >> 2);
+ for (j = 0; j < 4; j++) {
+ if (RS8(mask, j, 0x1))
+ reta_conf[idx].reta[shift + j] =
+ (uint16_t)RS32(reta, 8 * j, 0xFF);
+ }
+ }
+
+ return 0;
+}
+
+static int
+ngbe_add_rar(struct rte_eth_dev *dev, struct rte_ether_addr *mac_addr,
+ uint32_t index, uint32_t pool)
+{
+ struct ngbe_hw *hw = ngbe_dev_hw(dev);
+ uint32_t enable_addr = 1;
+
+ return ngbe_set_rar(hw, index, mac_addr->addr_bytes,
+ pool, enable_addr);
+}
+
+static void
+ngbe_remove_rar(struct rte_eth_dev *dev, uint32_t index)
+{
+ struct ngbe_hw *hw = ngbe_dev_hw(dev);
+
+ ngbe_clear_rar(hw, index);
+}
+
+static int
+ngbe_set_default_mac_addr(struct rte_eth_dev *dev, struct rte_ether_addr *addr)
+{
+ struct rte_pci_device *pci_dev = RTE_ETH_DEV_TO_PCI(dev);
+
+ ngbe_remove_rar(dev, 0);
+ ngbe_add_rar(dev, addr, 0, pci_dev->max_vfs);
+
+ return 0;
+}
+
+static int
+ngbe_dev_mtu_set(struct rte_eth_dev *dev, uint16_t mtu)
+{
+ struct ngbe_hw *hw = ngbe_dev_hw(dev);
+ uint32_t frame_size = mtu + RTE_ETHER_HDR_LEN + RTE_ETHER_CRC_LEN + 4;
+ struct rte_eth_dev_data *dev_data = dev->data;
+
+ /* If device is started, refuse mtu that requires the support of
+ * scattered packets when this feature has not been enabled before.
+ */
+ if (dev_data->dev_started && !dev_data->scattered_rx &&
+ (frame_size + 2 * NGBE_VLAN_TAG_SIZE >
+ dev->data->min_rx_buf_size - RTE_PKTMBUF_HEADROOM)) {
+ PMD_INIT_LOG(ERR, "Stop port first.");
+ return -EINVAL;
+ }
+
+ if (hw->mode)
+ wr32m(hw, NGBE_FRMSZ, NGBE_FRMSZ_MAX_MASK,
+ NGBE_FRAME_SIZE_MAX);
+ else
+ wr32m(hw, NGBE_FRMSZ, NGBE_FRMSZ_MAX_MASK,
+ NGBE_FRMSZ_MAX(frame_size));
+
+ return 0;
+}
+
+static uint32_t
+ngbe_uta_vector(struct ngbe_hw *hw, struct rte_ether_addr *uc_addr)
+{
+ uint32_t vector = 0;
+
+ switch (hw->mac.mc_filter_type) {
+ case 0: /* use bits [47:36] of the address */
+ vector = ((uc_addr->addr_bytes[4] >> 4) |
+ (((uint16_t)uc_addr->addr_bytes[5]) << 4));
+ break;
+ case 1: /* use bits [46:35] of the address */
+ vector = ((uc_addr->addr_bytes[4] >> 3) |
+ (((uint16_t)uc_addr->addr_bytes[5]) << 5));
+ break;
+ case 2: /* use bits [45:34] of the address */
+ vector = ((uc_addr->addr_bytes[4] >> 2) |
+ (((uint16_t)uc_addr->addr_bytes[5]) << 6));
+ break;
+ case 3: /* use bits [43:32] of the address */
+ vector = ((uc_addr->addr_bytes[4]) |
+ (((uint16_t)uc_addr->addr_bytes[5]) << 8));
+ break;
+ default: /* Invalid mc_filter_type */
+ break;
+ }
+
+ /* vector can only be 12-bits or boundary will be exceeded */
+ vector &= 0xFFF;
+ return vector;
+}
+
+static int
+ngbe_uc_hash_table_set(struct rte_eth_dev *dev,
+ struct rte_ether_addr *mac_addr, uint8_t on)
+{
+ uint32_t vector;
+ uint32_t uta_idx;
+ uint32_t reg_val;
+ uint32_t uta_mask;
+ uint32_t psrctl;
+
+ struct ngbe_hw *hw = ngbe_dev_hw(dev);
+ struct ngbe_uta_info *uta_info = NGBE_DEV_UTA_INFO(dev);
+
+ vector = ngbe_uta_vector(hw, mac_addr);
+ uta_idx = (vector >> 5) & 0x7F;
+ uta_mask = 0x1UL << (vector & 0x1F);
+
+ if (!!on == !!(uta_info->uta_shadow[uta_idx] & uta_mask))
+ return 0;
+
+ reg_val = rd32(hw, NGBE_UCADDRTBL(uta_idx));
+ if (on) {
+ uta_info->uta_in_use++;
+ reg_val |= uta_mask;
+ uta_info->uta_shadow[uta_idx] |= uta_mask;
+ } else {
+ uta_info->uta_in_use--;
+ reg_val &= ~uta_mask;
+ uta_info->uta_shadow[uta_idx] &= ~uta_mask;
+ }
+
+ wr32(hw, NGBE_UCADDRTBL(uta_idx), reg_val);
+
+ psrctl = rd32(hw, NGBE_PSRCTL);
+ if (uta_info->uta_in_use > 0)
+ psrctl |= NGBE_PSRCTL_UCHFENA;
+ else
+ psrctl &= ~NGBE_PSRCTL_UCHFENA;
+
+ psrctl &= ~NGBE_PSRCTL_ADHF12_MASK;
+ psrctl |= NGBE_PSRCTL_ADHF12(hw->mac.mc_filter_type);
+ wr32(hw, NGBE_PSRCTL, psrctl);
+
+ return 0;
+}
+
+static int
+ngbe_uc_all_hash_table_set(struct rte_eth_dev *dev, uint8_t on)
+{
+ struct ngbe_hw *hw = ngbe_dev_hw(dev);
+ struct ngbe_uta_info *uta_info = NGBE_DEV_UTA_INFO(dev);
+ uint32_t psrctl;
+ int i;
+
+ if (on) {
+ for (i = 0; i < RTE_ETH_VMDQ_NUM_UC_HASH_ARRAY; i++) {
+ uta_info->uta_shadow[i] = ~0;
+ wr32(hw, NGBE_UCADDRTBL(i), ~0);
+ }
+ } else {
+ for (i = 0; i < RTE_ETH_VMDQ_NUM_UC_HASH_ARRAY; i++) {
+ uta_info->uta_shadow[i] = 0;
+ wr32(hw, NGBE_UCADDRTBL(i), 0);
+ }
+ }
+
+ psrctl = rd32(hw, NGBE_PSRCTL);
+ if (on)
+ psrctl |= NGBE_PSRCTL_UCHFENA;
+ else
+ psrctl &= ~NGBE_PSRCTL_UCHFENA;
+
+ psrctl &= ~NGBE_PSRCTL_ADHF12_MASK;
+ psrctl |= NGBE_PSRCTL_ADHF12(hw->mac.mc_filter_type);
+ wr32(hw, NGBE_PSRCTL, psrctl);
+
+ return 0;
+}
+