/* 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;
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.