/* ixgbe allocates num_tx_queues and num_rx_queues symmetrically so * we set the num_rx_queues to evaluate to num_tx_queues. This is * used because we do not have a good way to get the max number of * rx queues with CONFIG_RPS disabled.
*/ #define IXGBE_NUM_RX_QUEUES netdev->num_tx_queues
staticconstchar ixgbe_gstrings_test[][ETH_GSTRING_LEN] = { "Register test (offline)", "Eeprom test (offline)", "Interrupt test (offline)", "Loopback test (offline)", "Link test (on/offline)"
}; #define IXGBE_TEST_LEN sizeof(ixgbe_gstrings_test) / ETH_GSTRING_LEN
/* set the supported link speeds */ if (supported_link & IXGBE_LINK_SPEED_10GB_FULL) {
ixgbe_set_supported_10gtypes(hw, cmd);
ixgbe_set_advertising_10gtypes(hw, cmd);
} if (supported_link & IXGBE_LINK_SPEED_5GB_FULL)
ethtool_link_ksettings_add_link_mode(cmd, supported,
5000baseT_Full);
if (supported_link & IXGBE_LINK_SPEED_2_5GB_FULL)
ethtool_link_ksettings_add_link_mode(cmd, supported,
2500baseT_Full);
/* Determine the remaining settings based on the PHY type. */ switch (adapter->hw.phy.type) { case ixgbe_phy_tn: case ixgbe_phy_aq: case ixgbe_phy_x550em_ext_t: case ixgbe_phy_fw: case ixgbe_phy_cu_unknown:
ethtool_link_ksettings_add_link_mode(cmd, supported, TP);
ethtool_link_ksettings_add_link_mode(cmd, advertising, TP);
cmd->base.port = PORT_TP; break; case ixgbe_phy_qt:
ethtool_link_ksettings_add_link_mode(cmd, supported, FIBRE);
ethtool_link_ksettings_add_link_mode(cmd, advertising, FIBRE);
cmd->base.port = PORT_FIBRE; break; case ixgbe_phy_nl: case ixgbe_phy_sfp_passive_tyco: case ixgbe_phy_sfp_passive_unknown: case ixgbe_phy_sfp_ftl: case ixgbe_phy_sfp_avago: case ixgbe_phy_sfp_intel: case ixgbe_phy_sfp_unknown: case ixgbe_phy_qsfp_passive_unknown: case ixgbe_phy_qsfp_active_unknown: case ixgbe_phy_qsfp_intel: case ixgbe_phy_qsfp_unknown: /* SFP+ devices, further checking needed */ switch (adapter->hw.phy.sfp_type) { case ixgbe_sfp_type_da_cu: case ixgbe_sfp_type_da_cu_core0: case ixgbe_sfp_type_da_cu_core1:
ethtool_link_ksettings_add_link_mode(cmd, supported,
FIBRE);
ethtool_link_ksettings_add_link_mode(cmd, advertising,
FIBRE);
cmd->base.port = PORT_DA; break; case ixgbe_sfp_type_sr: case ixgbe_sfp_type_lr: case ixgbe_sfp_type_srlr_core0: case ixgbe_sfp_type_srlr_core1: case ixgbe_sfp_type_1g_sx_core0: case ixgbe_sfp_type_1g_sx_core1: case ixgbe_sfp_type_1g_lx_core0: case ixgbe_sfp_type_1g_lx_core1: case ixgbe_sfp_type_1g_bx_core0: case ixgbe_sfp_type_1g_bx_core1:
ethtool_link_ksettings_add_link_mode(cmd, supported,
FIBRE);
ethtool_link_ksettings_add_link_mode(cmd, advertising,
FIBRE);
cmd->base.port = PORT_FIBRE; break; case ixgbe_sfp_type_not_present:
ethtool_link_ksettings_add_link_mode(cmd, supported,
FIBRE);
ethtool_link_ksettings_add_link_mode(cmd, advertising,
FIBRE);
cmd->base.port = PORT_NONE; break; case ixgbe_sfp_type_1g_cu_core0: case ixgbe_sfp_type_1g_cu_core1:
ethtool_link_ksettings_add_link_mode(cmd, supported,
TP);
ethtool_link_ksettings_add_link_mode(cmd, advertising,
TP);
cmd->base.port = PORT_TP; break; case ixgbe_sfp_type_unknown: default:
ethtool_link_ksettings_add_link_mode(cmd, supported,
FIBRE);
ethtool_link_ksettings_add_link_mode(cmd, advertising,
FIBRE);
cmd->base.port = PORT_OTHER; break;
} break; case ixgbe_phy_xaui:
ethtool_link_ksettings_add_link_mode(cmd, supported,
FIBRE);
ethtool_link_ksettings_add_link_mode(cmd, advertising,
FIBRE);
cmd->base.port = PORT_NONE; break; case ixgbe_phy_unknown: case ixgbe_phy_generic: case ixgbe_phy_sfp_unsupported: default:
ethtool_link_ksettings_add_link_mode(cmd, supported,
FIBRE);
ethtool_link_ksettings_add_link_mode(cmd, advertising,
FIBRE);
cmd->base.port = PORT_OTHER; break;
}
/* Indicate pause support */
ethtool_link_ksettings_add_link_mode(cmd, supported, Pause);
if ((hw->phy.media_type == ixgbe_media_type_copper) ||
(hw->phy.multispeed_fiber)) { /* * this function does not support duplex forcing, but can * limit the advertising of the adapter to the specified speed
*/ if (!linkmode_subset(cmd->link_modes.advertising,
cmd->link_modes.supported)) return -EINVAL;
/* only allow one speed at a time if no autoneg */ if (!cmd->base.autoneg && hw->phy.multispeed_fiber) { if (ethtool_link_ksettings_test_link_mode(cmd, advertising,
10000baseT_Full) &&
ethtool_link_ksettings_test_link_mode(cmd, advertising,
1000baseT_Full)) return -EINVAL;
}
old = hw->phy.autoneg_advertised;
advertised = 0; if (ethtool_link_ksettings_test_link_mode(cmd, advertising,
10000baseT_Full))
advertised |= IXGBE_LINK_SPEED_10GB_FULL; if (ethtool_link_ksettings_test_link_mode(cmd, advertising,
5000baseT_Full))
advertised |= IXGBE_LINK_SPEED_5GB_FULL; if (ethtool_link_ksettings_test_link_mode(cmd, advertising,
2500baseT_Full))
advertised |= IXGBE_LINK_SPEED_2_5GB_FULL; if (ethtool_link_ksettings_test_link_mode(cmd, advertising,
1000baseT_Full))
advertised |= IXGBE_LINK_SPEED_1GB_FULL;
if (ethtool_link_ksettings_test_link_mode(cmd, advertising,
100baseT_Full))
advertised |= IXGBE_LINK_SPEED_100_FULL;
if (ethtool_link_ksettings_test_link_mode(cmd, advertising,
10baseT_Full))
advertised |= IXGBE_LINK_SPEED_10_FULL;
if (old == advertised) return err; /* this sets the link speed and restarts auto-neg */ while (test_and_set_bit(__IXGBE_IN_SFP_INIT, &adapter->state))
usleep_range(1000, 2000);
hw->mac.autotry_restart = true;
err = hw->mac.ops.setup_link(hw, advertised, true); if (err) {
e_info(probe, "setup link failed with code %d\n", err);
hw->mac.ops.setup_link(hw, old, true);
}
clear_bit(__IXGBE_IN_SFP_INIT, &adapter->state);
} else { /* in this case we currently only support 10Gb/FULL */
u32 speed = cmd->base.speed;
/* If the thing changed then we'll update and use new autoneg. */ if (memcmp(fc, &hw->fc, sizeof(*fc))) {
hw->fc = *fc; if (netif_running(netdev))
ixgbe_reinit_locked(adapter); else
ixgbe_reset(adapter);
}
}
/* 82598 does no support link flow control with DCB enabled */ if ((hw->mac.type == ixgbe_mac_82598EB) &&
(adapter->flags & IXGBE_FLAG_DCB_ENABLED)) return -EINVAL;
/* some devices do not support autoneg of link flow control */ if ((pause->autoneg == AUTONEG_ENABLE) &&
!ixgbe_device_supports_autoneg_fc(hw)) return -EINVAL;
/* DCB */
regs_buff[829] = IXGBE_READ_REG(hw, IXGBE_RMCS); /* same as FCCFG */
regs_buff[831] = IXGBE_READ_REG(hw, IXGBE_PDPMCS); /* same as RTTPCS */
switch (hw->mac.type) { case ixgbe_mac_82598EB:
regs_buff[830] = IXGBE_READ_REG(hw, IXGBE_DPMCS);
regs_buff[832] = IXGBE_READ_REG(hw, IXGBE_RUPPBMR); for (i = 0; i < 8; i++)
regs_buff[833 + i] =
IXGBE_READ_REG(hw, IXGBE_RT2CR(i)); for (i = 0; i < 8; i++)
regs_buff[841 + i] =
IXGBE_READ_REG(hw, IXGBE_RT2SR(i)); for (i = 0; i < 8; i++)
regs_buff[849 + i] =
IXGBE_READ_REG(hw, IXGBE_TDTQ2TCCR(i)); for (i = 0; i < 8; i++)
regs_buff[857 + i] =
IXGBE_READ_REG(hw, IXGBE_TDTQ2TCSR(i)); break; case ixgbe_mac_82599EB: case ixgbe_mac_X540: case ixgbe_mac_X550: case ixgbe_mac_X550EM_x: case ixgbe_mac_x550em_a:
regs_buff[830] = IXGBE_READ_REG(hw, IXGBE_RTTDCS);
regs_buff[832] = IXGBE_READ_REG(hw, IXGBE_RTRPCS); for (i = 0; i < 8; i++)
regs_buff[833 + i] =
IXGBE_READ_REG(hw, IXGBE_RTRPT4C(i)); for (i = 0; i < 8; i++)
regs_buff[841 + i] =
IXGBE_READ_REG(hw, IXGBE_RTRPT4S(i)); for (i = 0; i < 8; i++)
regs_buff[849 + i] =
IXGBE_READ_REG(hw, IXGBE_RTTDT2C(i)); for (i = 0; i < 8; i++)
regs_buff[857 + i] =
IXGBE_READ_REG(hw, IXGBE_RTTDT2S(i)); break; default: break;
}
for (i = 0; i < 8; i++)
regs_buff[865 + i] =
IXGBE_READ_REG(hw, IXGBE_TDPT2TCCR(i)); /* same as RTTPT2C */ for (i = 0; i < 8; i++)
regs_buff[873 + i] =
IXGBE_READ_REG(hw, IXGBE_TDPT2TCSR(i)); /* same as RTTPT2S */
if (eeprom->offset & 1) { /* * need read/modify/write of first changed EEPROM word * only the second byte of the word is being modified
*/
ret_val = hw->eeprom.ops.read(hw, first_word, &eeprom_buff[0]); if (ret_val) goto err;
ptr++;
} if ((eeprom->offset + eeprom->len) & 1) { /* * need read/modify/write of last changed EEPROM word * only the first byte of the word is being modified
*/
ret_val = hw->eeprom.ops.read(hw, last_word,
&eeprom_buff[last_word - first_word]); if (ret_val) goto err;
}
/* Device's eeprom is always little-endian, word addressable */ for (i = 0; i < last_word - first_word + 1; i++)
le16_to_cpus(&eeprom_buff[i]);
memcpy(ptr, bytes, eeprom->len);
for (i = 0; i < last_word - first_word + 1; i++)
cpu_to_le16s(&eeprom_buff[i]);
if ((new_tx_count == adapter->tx_ring_count) &&
(new_rx_count == adapter->rx_ring_count)) { /* nothing to do */ return 0;
}
while (test_and_set_bit(__IXGBE_RESETTING, &adapter->state))
usleep_range(1000, 2000);
if (!netif_running(adapter->netdev)) { for (i = 0; i < adapter->num_tx_queues; i++)
adapter->tx_ring[i]->count = new_tx_count; for (i = 0; i < adapter->num_xdp_queues; i++)
adapter->xdp_ring[i]->count = new_tx_count; for (i = 0; i < adapter->num_rx_queues; i++)
adapter->rx_ring[i]->count = new_rx_count;
adapter->tx_ring_count = new_tx_count;
adapter->xdp_ring_count = new_tx_count;
adapter->rx_ring_count = new_rx_count; goto clear_reset;
}
/* allocate temporary buffer to store rings in */
i = max_t(int, adapter->num_tx_queues + adapter->num_xdp_queues,
adapter->num_rx_queues);
temp_ring = vmalloc(array_size(i, sizeof(struct ixgbe_ring)));
if (!temp_ring) {
err = -ENOMEM; goto clear_reset;
}
ixgbe_down(adapter);
/* * Setup new Tx resources and free the old Tx resources in that order. * We can then assign the new resources to the rings via a memcpy. * The advantage to this approach is that we are guaranteed to still * have resources even in the case of an allocation failure.
*/ if (new_tx_count != adapter->tx_ring_count) { for (i = 0; i < adapter->num_tx_queues; i++) {
memcpy(&temp_ring[i], adapter->tx_ring[i], sizeof(struct ixgbe_ring));
temp_ring[i].count = new_tx_count;
err = ixgbe_setup_tx_resources(&temp_ring[i]); if (err) { while (i) {
i--;
ixgbe_free_tx_resources(&temp_ring[i]);
} goto err_setup;
}
}
/* Repeat the process for the Rx rings if needed */ if (new_rx_count != adapter->rx_ring_count) { for (i = 0; i < adapter->num_rx_queues; i++) {
memcpy(&temp_ring[i], adapter->rx_ring[i], sizeof(struct ixgbe_ring));
/* Clear copied XDP RX-queue info */
memset(&temp_ring[i].xdp_rxq, 0, sizeof(temp_ring[i].xdp_rxq));
temp_ring[i].count = new_rx_count;
err = ixgbe_setup_rx_resources(adapter, &temp_ring[i]); if (err) { while (i) {
i--;
ixgbe_free_rx_resources(&temp_ring[i]);
} goto err_setup;
}
}
for (i = 0; i < adapter->num_rx_queues; i++) {
ixgbe_free_rx_resources(adapter->rx_ring[i]);
/* ethtool register test data */ struct ixgbe_reg_test {
u16 reg;
u8 array_len;
u8 test_type;
u32 mask;
u32 write;
};
/* In the hardware, registers are laid out either singly, in arrays * spaced 0x40 bytes apart, or in contiguous tables. We assume * most tests take place on arrays or single registers (handled * as a single-element array) and special-case the tables. * Table tests are always pattern tests. * * We also make provision for some required setup steps by specifying * registers to be written without any read-back testing.
*/
if (ixgbe_removed(adapter->hw.hw_addr)) {
e_err(drv, "Adapter removed - register test blocked\n");
*data = 1; return 1;
} switch (adapter->hw.mac.type) { case ixgbe_mac_82598EB:
toggle = 0x7FFFF3FF;
test = reg_test_82598; break; case ixgbe_mac_82599EB: case ixgbe_mac_X540: case ixgbe_mac_X550: case ixgbe_mac_X550EM_x: case ixgbe_mac_x550em_a: case ixgbe_mac_e610:
toggle = 0x7FFFF30F;
test = reg_test_82599; break; default:
*data = 1; return 1;
}
/* * Because the status register is such a special case, * we handle it separately from the rest of the register * tests. Some bits are read-only, some toggle, and some * are writeable on newer MACs.
*/
before = ixgbe_read_reg(&adapter->hw, IXGBE_STATUS);
value = (ixgbe_read_reg(&adapter->hw, IXGBE_STATUS) & toggle);
ixgbe_write_reg(&adapter->hw, IXGBE_STATUS, toggle);
after = ixgbe_read_reg(&adapter->hw, IXGBE_STATUS) & toggle; if (value != after) {
e_err(drv, "failed STATUS register test got: 0x%08X expected: 0x%08X\n",
after, value);
*data = 1; return 1;
} /* restore previous status */
ixgbe_write_reg(&adapter->hw, IXGBE_STATUS, before);
/* * Perform the remainder of the register test, looping through * the test table until we either fail or reach the null entry.
*/ while (test->reg) { for (i = 0; i < test->array_len; i++) { bool b = false;
switch (test->test_type) { case PATTERN_TEST:
b = reg_pattern_test(adapter, data,
test->reg + (i * 0x40),
test->mask,
test->write); break; case SET_READ_TEST:
b = reg_set_and_check(adapter, data,
test->reg + (i * 0x40),
test->mask,
test->write); break; case WRITE_NO_TEST:
ixgbe_write_reg(&adapter->hw,
test->reg + (i * 0x40),
test->write); break; case TABLE32_TEST:
b = reg_pattern_test(adapter, data,
test->reg + (i * 4),
test->mask,
test->write); break; case TABLE64_TEST_LO:
b = reg_pattern_test(adapter, data,
test->reg + (i * 8),
test->mask,
test->write); break; case TABLE64_TEST_HI:
b = reg_pattern_test(adapter, data,
(test->reg + 4) + (i * 8),
test->mask,
test->write); break;
} if (b) return 1;
}
test++;
}
/* Hook up test interrupt handler just for this test */ if (adapter->msix_entries) { /* NOTE: we don't test MSI-X interrupts here, yet */ return 0;
} elseif (adapter->flags & IXGBE_FLAG_MSI_ENABLED) {
shared_int = false; if (request_irq(irq, ixgbe_test_intr, 0, netdev->name,
netdev)) {
*data = 1; return -1;
}
} elseif (!request_irq(irq, ixgbe_test_intr, IRQF_PROBE_SHARED,
netdev->name, netdev)) {
shared_int = false;
} elseif (request_irq(irq, ixgbe_test_intr, IRQF_SHARED,
netdev->name, netdev)) {
*data = 1; return -1;
}
e_info(hw, "testing %s interrupt\n", shared_int ? "shared" : "unshared");
/* Disable all the interrupts */
IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMC, 0xFFFFFFFF);
IXGBE_WRITE_FLUSH(&adapter->hw);
usleep_range(10000, 20000);
/* Test each interrupt */ for (; i < 10; i++) { /* Interrupt to test */
mask = BIT(i);
if (!shared_int) { /* * Disable the interrupts to be reported in * the cause register and then force the same * interrupt and see if one gets posted. If * an interrupt was posted to the bus, the * test failed.
*/
adapter->test_icr = 0;
IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMC,
~mask & 0x00007FFF);
IXGBE_WRITE_REG(&adapter->hw, IXGBE_EICS,
~mask & 0x00007FFF);
IXGBE_WRITE_FLUSH(&adapter->hw);
usleep_range(10000, 20000);
/* * Enable the interrupt to be reported in the cause * register and then force the same interrupt and see * if one gets posted. If an interrupt was not posted * to the bus, the test failed.
*/
adapter->test_icr = 0;
IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMS, mask);
IXGBE_WRITE_REG(&adapter->hw, IXGBE_EICS, mask);
IXGBE_WRITE_FLUSH(&adapter->hw);
usleep_range(10000, 20000);
if (!(adapter->test_icr & mask)) {
*data = 4; break;
}
if (!shared_int) { /* * Disable the other interrupts to be reported in * the cause register and then force the other * interrupts and see if any get posted. If * an interrupt was posted to the bus, the * test failed.
*/
adapter->test_icr = 0;
IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMC,
~mask & 0x00007FFF);
IXGBE_WRITE_REG(&adapter->hw, IXGBE_EICS,
~mask & 0x00007FFF);
IXGBE_WRITE_FLUSH(&adapter->hw);
usleep_range(10000, 20000);
if (adapter->test_icr) {
*data = 5; break;
}
}
}
/* Disable all the interrupts */
IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMC, 0xFFFFFFFF);
IXGBE_WRITE_FLUSH(&adapter->hw);
usleep_range(10000, 20000);
/* Unhook test interrupt handler */
free_irq(irq, netdev);
return *data;
}
staticvoid ixgbe_free_desc_rings(struct ixgbe_adapter *adapter)
{ /* Shut down the DMA engines now so they can be reinitialized later, * since the test rings and normally used rings should overlap on * queue 0 we can just use the standard disable Rx/Tx calls and they * will take care of disabling the test rings for us.
*/
err = ixgbe_setup_tx_resources(tx_ring); if (err) return 1;
switch (adapter->hw.mac.type) { case ixgbe_mac_82599EB: case ixgbe_mac_X540: case ixgbe_mac_X550: case ixgbe_mac_X550EM_x: case ixgbe_mac_x550em_a: case ixgbe_mac_e610:
reg_data = IXGBE_READ_REG(&adapter->hw, IXGBE_DMATXCTL);
reg_data |= IXGBE_DMATXCTL_TE;
IXGBE_WRITE_REG(&adapter->hw, IXGBE_DMATXCTL, reg_data); break; default: break;
}
/* X540 and X550 needs to set the MACC.FLU bit to force link up */ switch (adapter->hw.mac.type) { case ixgbe_mac_X540: case ixgbe_mac_X550: case ixgbe_mac_X550EM_x: case ixgbe_mac_x550em_a: case ixgbe_mac_e610:
reg_data = IXGBE_READ_REG(hw, IXGBE_MACC);
reg_data |= IXGBE_MACC_FLU;
IXGBE_WRITE_REG(hw, IXGBE_MACC, reg_data); break; default: if (hw->mac.orig_autoc) {
reg_data = hw->mac.orig_autoc | IXGBE_AUTOC_FLU;
IXGBE_WRITE_REG(hw, IXGBE_AUTOC, reg_data);
} else { return 10;
}
}
IXGBE_WRITE_FLUSH(hw);
usleep_range(10000, 20000);
/* Disable Atlas Tx lanes; re-enabled in reset path */ if (hw->mac.type == ixgbe_mac_82598EB) {
u8 atlas;
/* increment Rx next to clean counter */
rx_ntc++; if (rx_ntc == rx_ring->count)
rx_ntc = 0;
/* fetch next descriptor */
rx_desc = IXGBE_RX_DESC(rx_ring, rx_ntc);
}
netdev_tx_reset_queue(txring_txq(tx_ring));
/* re-map buffers to ring, store next to clean values */
ixgbe_alloc_rx_buffers(rx_ring, count);
rx_ring->next_to_clean = rx_ntc;
tx_ring->next_to_clean = tx_ntc;
/* DCB can modify the frames on Tx */
adapter->flags &= ~IXGBE_FLAG_DCB_ENABLED;
/* allocate test skb */
skb = alloc_skb(size, GFP_KERNEL); if (!skb) return 11;
/* place data into test skb */
ixgbe_create_lbtest_frame(skb, size);
skb_put(skb, size);
/* * Calculate the loop count based on the largest descriptor ring * The idea is to wrap the largest ring a number of times using 64 * send/receive pairs during each loop
*/
for (j = 0; j <= lc; j++) { /* reset count of good packets */
good_cnt = 0;
/* place 64 packets on the transmit queue*/ for (i = 0; i < 64; i++) {
skb_get(skb);
tx_ret_val = ixgbe_xmit_frame_ring(skb,
adapter,
tx_ring); if (tx_ret_val == NETDEV_TX_OK)
good_cnt++;
}
if (good_cnt != 64) {
ret_val = 12; break;
}
/* allow 200 milliseconds for packets to go from Tx to Rx */
msleep(200);
/* Link test performed before hardware reset so autoneg doesn't * interfere with test result
*/ if (ixgbe_link_test(adapter, &data[4]))
eth_test->flags |= ETH_TEST_FL_FAILED;
if (if_running) /* indicate we're in test mode */
ixgbe_close(netdev); else
ixgbe_reset(adapter);
e_info(hw, "register testing starting\n"); if (ixgbe_reg_test(adapter, &data[0]))
eth_test->flags |= ETH_TEST_FL_FAILED;
/* If SRIOV or VMDq is enabled then skip MAC
* loopback diagnostic. */ if (adapter->flags & (IXGBE_FLAG_SRIOV_ENABLED |
IXGBE_FLAG_VMDQ_ENABLED)) {
e_info(hw, "Skip MAC loopback diagnostic in VT mode\n");
data[3] = 0; goto skip_loopback;
}
/* only valid if in constant ITR mode */ if (adapter->rx_itr_setting <= 1)
ec->rx_coalesce_usecs = adapter->rx_itr_setting; else
ec->rx_coalesce_usecs = adapter->rx_itr_setting >> 2;
/* if in mixed tx/rx queues per vector mode, report only rx settings */ if (adapter->q_vector[0]->tx.count && adapter->q_vector[0]->rx.count) return 0;
/* only valid if in constant ITR mode */ if (adapter->tx_itr_setting <= 1)
ec->tx_coalesce_usecs = adapter->tx_itr_setting; else
ec->tx_coalesce_usecs = adapter->tx_itr_setting >> 2;
return 0;
}
/* * this function must be called before setting the new value of * rx_itr_setting
*/ staticbool ixgbe_update_rsc(struct ixgbe_adapter *adapter)
{ struct net_device *netdev = adapter->netdev;
/* nothing to do if LRO or RSC are not enabled */ if (!(adapter->flags2 & IXGBE_FLAG2_RSC_CAPABLE) ||
!(netdev->features & NETIF_F_LRO)) returnfalse;
/* check the feature flag value and enable RSC if necessary */ if (adapter->rx_itr_setting == 1 ||
adapter->rx_itr_setting > IXGBE_MIN_RSC_ITR) { if (!(adapter->flags2 & IXGBE_FLAG2_RSC_ENABLED)) {
adapter->flags2 |= IXGBE_FLAG2_RSC_ENABLED;
e_info(probe, "rx-usecs value high enough to re-enable RSC\n"); returntrue;
} /* if interrupt rate is too high then disable RSC */
} elseif (adapter->flags2 & IXGBE_FLAG2_RSC_ENABLED) {
adapter->flags2 &= ~IXGBE_FLAG2_RSC_ENABLED;
e_info(probe, "rx-usecs set too low, disabling RSC\n"); returntrue;
} returnfalse;
}
/* detect ITR changes that require update of TXDCTL.WTHRESH */ if ((adapter->tx_itr_setting != 1) &&
(adapter->tx_itr_setting < IXGBE_100K_ITR)) { if ((tx_itr_prev == 1) ||
(tx_itr_prev >= IXGBE_100K_ITR))
need_reset = true;
} else { if ((tx_itr_prev != 1) &&
(tx_itr_prev < IXGBE_100K_ITR))
need_reset = true;
}
/* check the old value and enable RSC if necessary */
need_reset |= ixgbe_update_rsc(adapter);
for (i = 0; i < adapter->num_q_vectors; i++) {
q_vector = adapter->q_vector[i]; if (q_vector->tx.count && !q_vector->rx.count) /* tx only */
q_vector->itr = tx_itr_param; else /* rx only or mixed */
q_vector->itr = rx_itr_param;
ixgbe_write_eitr(q_vector);
}
/* * do reset here at the end to make sure EITR==0 case is handled * correctly w.r.t stopping tx, and changing TXDCTL.WTHRESH settings * also locks in RSC enable/disable which requires reset
*/ if (need_reset)
ixgbe_do_reset(netdev);
/* Report default options for RSS on ixgbe */ switch (cmd->flow_type) { case TCP_V4_FLOW:
cmd->data |= RXH_L4_B_0_1 | RXH_L4_B_2_3;
fallthrough; case UDP_V4_FLOW: if (adapter->flags2 & IXGBE_FLAG2_RSS_FIELD_IPV4_UDP)
cmd->data |= RXH_L4_B_0_1 | RXH_L4_B_2_3;
fallthrough; case SCTP_V4_FLOW: case AH_ESP_V4_FLOW: case AH_V4_FLOW: case ESP_V4_FLOW: case IPV4_FLOW:
cmd->data |= RXH_IP_SRC | RXH_IP_DST; break; case TCP_V6_FLOW:
cmd->data |= RXH_L4_B_0_1 | RXH_L4_B_2_3;
fallthrough; case UDP_V6_FLOW: if (adapter->flags2 & IXGBE_FLAG2_RSS_FIELD_IPV6_UDP)
cmd->data |= RXH_L4_B_0_1 | RXH_L4_B_2_3;
fallthrough; case SCTP_V6_FLOW: case AH_ESP_V6_FLOW: case AH_V6_FLOW: case ESP_V6_FLOW: case IPV6_FLOW:
cmd->data |= RXH_IP_SRC | RXH_IP_DST; break; default: return -EINVAL;
}
hlist_for_each_entry_safe(rule, node2,
&adapter->fdir_filter_list, fdir_node) { /* hash found, or no matching entry */ if (rule->sw_idx >= sw_idx) break;
parent = rule;
}
/* if there is an old rule occupying our place remove it */ if (rule && (rule->sw_idx == sw_idx)) { if (!input || (rule->filter.formatted.bkt_hash !=
input->filter.formatted.bkt_hash)) {
err = ixgbe_fdir_erase_perfect_filter_82599(hw,
&rule->filter,
sw_idx);
}
/* * If no input this was a delete, err should be 0 if a rule was * successfully found and removed from the list else -EINVAL
*/ if (!input) return err;
/* initialize node and set software index */
INIT_HLIST_NODE(&input->fdir_node);
/* add filter to the list */ if (parent)
hlist_add_behind(&input->fdir_node, &parent->fdir_node); else
hlist_add_head(&input->fdir_node,
&adapter->fdir_filter_list);
/* update counts */
adapter->fdir_filter_count++;
return 0;
}
staticint ixgbe_flowspec_to_flow_type(struct ethtool_rx_flow_spec *fsp,
u8 *flow_type)
{ switch (fsp->flow_type & ~FLOW_EXT) { case TCP_V4_FLOW:
*flow_type = IXGBE_ATR_FLOW_TYPE_TCPV4; break; case UDP_V4_FLOW:
*flow_type = IXGBE_ATR_FLOW_TYPE_UDPV4; break; case SCTP_V4_FLOW:
*flow_type = IXGBE_ATR_FLOW_TYPE_SCTPV4; break; case IP_USER_FLOW: switch (fsp->h_u.usr_ip4_spec.proto) { case IPPROTO_TCP:
*flow_type = IXGBE_ATR_FLOW_TYPE_TCPV4; break; case IPPROTO_UDP:
*flow_type = IXGBE_ATR_FLOW_TYPE_UDPV4; break; case IPPROTO_SCTP:
*flow_type = IXGBE_ATR_FLOW_TYPE_SCTPV4; break; case 0: if (!fsp->m_u.usr_ip4_spec.proto) {
*flow_type = IXGBE_ATR_FLOW_TYPE_IPV4; break;
}
fallthrough; default: return 0;
} break; default: return 0;
}
if (!(adapter->flags & IXGBE_FLAG_FDIR_PERFECT_CAPABLE)) return -EOPNOTSUPP;
/* ring_cookie is a masked into a set of queues and ixgbe pools or * we use the drop index.
*/ if (fsp->ring_cookie == RX_CLS_FLOW_DISC) {
queue = IXGBE_FDIR_DROP_QUEUE;
} else {
u32 ring = ethtool_get_flow_spec_ring(fsp->ring_cookie);
u8 vf = ethtool_get_flow_spec_ring_vf(fsp->ring_cookie);
if (!vf && (ring >= adapter->num_rx_queues)) return -EINVAL; elseif (vf &&
((vf > adapter->num_vfs) ||
ring >= adapter->num_rx_queues_per_pool)) return -EINVAL;
/* Map the ring onto the absolute queue index */ if (!vf)
queue = adapter->rx_ring[ring]->reg_idx; else
queue = ((vf - 1) *
adapter->num_rx_queues_per_pool) + ring;
}
/* Don't allow indexes to exist outside of available space */ if (fsp->location >= ((1024 << adapter->fdir_pballoc) - 2)) {
e_err(drv, "Location out of range\n"); return -EINVAL;
}
input = kzalloc(sizeof(*input), GFP_ATOMIC); if (!input) return -ENOMEM;
memset(&mask, 0, sizeof(union ixgbe_atr_input));
/* set SW index */
input->sw_idx = fsp->location;
/* record flow type */ if (!ixgbe_flowspec_to_flow_type(fsp,
&input->filter.formatted.flow_type)) {
e_err(drv, "Unrecognized flow type\n"); goto err_out;
}
/* determine if we need to drop or route the packet */ if (fsp->ring_cookie == RX_CLS_FLOW_DISC)
input->action = IXGBE_FDIR_DROP_QUEUE; else
input->action = fsp->ring_cookie;
spin_lock(&adapter->fdir_perfect_lock);
if (hlist_empty(&adapter->fdir_filter_list)) { /* save mask and program input mask into HW */
memcpy(&adapter->fdir_mask, &mask, sizeof(mask));
err = ixgbe_fdir_set_input_mask_82599(hw, &mask); if (err) {
e_err(drv, "Error writing mask\n"); goto err_out_w_lock;
}
} elseif (memcmp(&adapter->fdir_mask, &mask, sizeof(mask))) {
e_err(drv, "Only one mask supported per port\n"); goto err_out_w_lock;
}
/* apply mask and compute/store hash */
ixgbe_atr_compute_perfect_hash_82599(&input->filter, &mask);
/* program filters to filter memory */
err = ixgbe_fdir_write_perfect_filter_82599(hw,
&input->filter, input->sw_idx, queue); if (err) goto err_out_w_lock;
/* * RSS does not support anything other than hashing * to queues on src and dst IPs and ports
*/ if (nfc->data & ~(RXH_IP_SRC | RXH_IP_DST |
RXH_L4_B_0_1 | RXH_L4_B_2_3)) return -EINVAL;
switch (nfc->flow_type) { case TCP_V4_FLOW: case TCP_V6_FLOW: if (!(nfc->data & RXH_IP_SRC) ||
!(nfc->data & RXH_IP_DST) ||
!(nfc->data & RXH_L4_B_0_1) ||
!(nfc->data & RXH_L4_B_2_3)) return -EINVAL; break; case UDP_V4_FLOW: if (!(nfc->data & RXH_IP_SRC) ||
!(nfc->data & RXH_IP_DST)) return -EINVAL; switch (nfc->data & (RXH_L4_B_0_1 | RXH_L4_B_2_3)) { case 0:
flags2 &= ~IXGBE_FLAG2_RSS_FIELD_IPV4_UDP; break; case (RXH_L4_B_0_1 | RXH_L4_B_2_3):
flags2 |= IXGBE_FLAG2_RSS_FIELD_IPV4_UDP; break; default: return -EINVAL;
} break; case UDP_V6_FLOW: if (!(nfc->data & RXH_IP_SRC) ||
!(nfc->data & RXH_IP_DST)) return -EINVAL; switch (nfc->data & (RXH_L4_B_0_1 | RXH_L4_B_2_3)) { case 0:
flags2 &= ~IXGBE_FLAG2_RSS_FIELD_IPV6_UDP; break; case (RXH_L4_B_0_1 | RXH_L4_B_2_3):
flags2 |= IXGBE_FLAG2_RSS_FIELD_IPV6_UDP; break; default: return -EINVAL;
} break; case AH_ESP_V4_FLOW: case AH_V4_FLOW: case ESP_V4_FLOW: case SCTP_V4_FLOW: case AH_ESP_V6_FLOW: case AH_V6_FLOW: case ESP_V6_FLOW: case SCTP_V6_FLOW: if (!(nfc->data & RXH_IP_SRC) ||
!(nfc->data & RXH_IP_DST) ||
(nfc->data & RXH_L4_B_0_1) ||
(nfc->data & RXH_L4_B_2_3)) return -EINVAL; break; default: return -EINVAL;
}
/* if we changed something we need to update flags */ if (flags2 != adapter->flags2) { struct ixgbe_hw *hw = &adapter->hw;
u32 mrqc; unsignedint pf_pool = adapter->num_vfs;
if ((flags2 & UDP_RSS_FLAGS) &&
!(adapter->flags2 & UDP_RSS_FLAGS))
e_warn(drv, "enabling UDP RSS: fragmented packets may arrive out of order to the stack above\n");
adapter->flags2 = flags2;
/* Perform hash on these packet types */
mrqc |= IXGBE_MRQC_RSS_FIELD_IPV4
| IXGBE_MRQC_RSS_FIELD_IPV4_TCP
| IXGBE_MRQC_RSS_FIELD_IPV6
| IXGBE_MRQC_RSS_FIELD_IPV6_TCP;
staticint ixgbe_set_rxnfc(struct net_device *dev, struct ethtool_rxnfc *cmd)
{ struct ixgbe_adapter *adapter = ixgbe_from_netdev(dev); int ret = -EOPNOTSUPP;
switch (cmd->cmd) { case ETHTOOL_SRXCLSRLINS:
ret = ixgbe_add_ethtool_fdir_entry(adapter, cmd); break; case ETHTOOL_SRXCLSRLDEL:
ret = ixgbe_del_ethtool_fdir_entry(adapter, cmd); break; default: break;
}
/* Check whether we support SFF-8472 or not */
status = hw->phy.ops.read_i2c_eeprom(hw,
IXGBE_SFF_SFF_8472_COMP,
&sff8472_rev); if (status) return -EIO;
/* addressing mode is not supported */
status = hw->phy.ops.read_i2c_eeprom(hw,
IXGBE_SFF_SFF_8472_SWAP,
&addr_mode); if (status) return -EIO;
if (addr_mode & IXGBE_SFF_ADDRESSING_MODE) {
e_err(drv, "Address change required to access page 0xA2, but not supported. Please report the module type to the driver maintainers.\n");
page_swap = true;
}
if (sff8472_rev == IXGBE_SFF_SFF_8472_UNSUP || page_swap ||
!(addr_mode & IXGBE_SFF_DDM_IMPLEMENTED)) { /* We have a SFP, but it does not support SFF-8472 */
modinfo->type = ETH_MODULE_SFF_8079;
modinfo->eeprom_len = ETH_MODULE_SFF_8079_LEN;
} else { /* We have a SFP which supports a revision of SFF-8472. */
modinfo->type = ETH_MODULE_SFF_8472;
modinfo->eeprom_len = ETH_MODULE_SFF_8472_LEN;
}
return 0;
}
staticint ixgbe_get_module_eeprom(struct net_device *dev, struct ethtool_eeprom *ee,
u8 *data)
{ struct ixgbe_adapter *adapter = ixgbe_from_netdev(dev); struct ixgbe_hw *hw = &adapter->hw; int status = -EFAULT;
u8 databyte = 0xFF; int i = 0;
if (ee->len == 0) return -EINVAL;
if (hw->phy.type == ixgbe_phy_fw) return -ENXIO;
for (i = ee->offset; i < ee->offset + ee->len; i++) { /* I2C reads can take long time */ if (test_bit(__IXGBE_IN_SFP_INIT, &adapter->state)) return -EBUSY;
if (i < ETH_MODULE_SFF_8079_LEN)
status = hw->phy.ops.read_i2c_eeprom(hw, i, &databyte); else
status = hw->phy.ops.read_i2c_sff8472(hw, i, &databyte);
rc = ixgbe_fw_phy_activity(hw, FW_PHY_ACT_UD_2, &info); if (rc) return rc;
for (i = 0; i < ARRAY_SIZE(ixgbe_lp_map); ++i) { if (info[0] & ixgbe_lp_map[i].lp_advertised)
linkmode_set_bit(ixgbe_lp_map[i].link_mode,
edata->lp_advertised);
}
for (i = 0; i < ARRAY_SIZE(ixgbe_ls_map); ++i) { if (hw->phy.eee_speeds_supported & ixgbe_ls_map[i].mac_speed)
linkmode_set_bit(ixgbe_ls_map[i].link_mode,
edata->supported);
}
for (i = 0; i < ARRAY_SIZE(ixgbe_ls_map); ++i) { if (hw->phy.eee_speeds_advertised & ixgbe_ls_map[i].mac_speed)
linkmode_set_bit(ixgbe_ls_map[i].link_mode,
edata->advertised);
}
ret_val = ixgbe_get_eee(netdev, &eee_data); if (ret_val) return ret_val;
if (eee_data.eee_enabled && !edata->eee_enabled) { if (eee_data.tx_lpi_enabled != edata->tx_lpi_enabled) {
e_err(drv, "Setting EEE tx-lpi is not supported\n"); return -EINVAL;
}
if (eee_data.tx_lpi_timer != edata->tx_lpi_timer) {
e_err(drv, "Setting EEE Tx LPI timer is not supported\n"); return -EINVAL;
}
if (!linkmode_equal(eee_data.advertised, edata->advertised)) {
e_err(drv, "Setting EEE advertised speeds is not supported\n"); return -EINVAL;
}
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.