162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/**************************************************************************** 362306a36Sopenharmony_ci * Driver for Solarflare network controllers and boards 462306a36Sopenharmony_ci * Copyright 2005-2006 Fen Systems Ltd. 562306a36Sopenharmony_ci * Copyright 2006-2012 Solarflare Communications Inc. 662306a36Sopenharmony_ci */ 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci#include <linux/netdevice.h> 962306a36Sopenharmony_ci#include <linux/module.h> 1062306a36Sopenharmony_ci#include <linux/delay.h> 1162306a36Sopenharmony_ci#include <linux/kernel_stat.h> 1262306a36Sopenharmony_ci#include <linux/pci.h> 1362306a36Sopenharmony_ci#include <linux/ethtool.h> 1462306a36Sopenharmony_ci#include <linux/ip.h> 1562306a36Sopenharmony_ci#include <linux/in.h> 1662306a36Sopenharmony_ci#include <linux/udp.h> 1762306a36Sopenharmony_ci#include <linux/rtnetlink.h> 1862306a36Sopenharmony_ci#include <linux/slab.h> 1962306a36Sopenharmony_ci#include "net_driver.h" 2062306a36Sopenharmony_ci#include "efx.h" 2162306a36Sopenharmony_ci#include "efx_common.h" 2262306a36Sopenharmony_ci#include "efx_channels.h" 2362306a36Sopenharmony_ci#include "nic.h" 2462306a36Sopenharmony_ci#include "mcdi_port_common.h" 2562306a36Sopenharmony_ci#include "selftest.h" 2662306a36Sopenharmony_ci#include "workarounds.h" 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_ci/* IRQ latency can be enormous because: 2962306a36Sopenharmony_ci * - All IRQs may be disabled on a CPU for a *long* time by e.g. a 3062306a36Sopenharmony_ci * slow serial console or an old IDE driver doing error recovery 3162306a36Sopenharmony_ci * - The PREEMPT_RT patches mostly deal with this, but also allow a 3262306a36Sopenharmony_ci * tasklet or normal task to be given higher priority than our IRQ 3362306a36Sopenharmony_ci * threads 3462306a36Sopenharmony_ci * Try to avoid blaming the hardware for this. 3562306a36Sopenharmony_ci */ 3662306a36Sopenharmony_ci#define IRQ_TIMEOUT HZ 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_ci/* 3962306a36Sopenharmony_ci * Loopback test packet structure 4062306a36Sopenharmony_ci * 4162306a36Sopenharmony_ci * The self-test should stress every RSS vector, and unfortunately 4262306a36Sopenharmony_ci * Falcon only performs RSS on TCP/UDP packets. 4362306a36Sopenharmony_ci */ 4462306a36Sopenharmony_cistruct efx_loopback_payload { 4562306a36Sopenharmony_ci char pad[2]; /* Ensures ip is 4-byte aligned */ 4662306a36Sopenharmony_ci struct_group_attr(packet, __packed, 4762306a36Sopenharmony_ci struct ethhdr header; 4862306a36Sopenharmony_ci struct iphdr ip; 4962306a36Sopenharmony_ci struct udphdr udp; 5062306a36Sopenharmony_ci __be16 iteration; 5162306a36Sopenharmony_ci char msg[64]; 5262306a36Sopenharmony_ci ); 5362306a36Sopenharmony_ci} __packed __aligned(4); 5462306a36Sopenharmony_ci#define EFX_LOOPBACK_PAYLOAD_LEN \ 5562306a36Sopenharmony_ci sizeof_field(struct efx_loopback_payload, packet) 5662306a36Sopenharmony_ci 5762306a36Sopenharmony_ci/* Loopback test source MAC address */ 5862306a36Sopenharmony_cistatic const u8 payload_source[ETH_ALEN] __aligned(2) = { 5962306a36Sopenharmony_ci 0x00, 0x0f, 0x53, 0x1b, 0x1b, 0x1b, 6062306a36Sopenharmony_ci}; 6162306a36Sopenharmony_ci 6262306a36Sopenharmony_cistatic const char payload_msg[] = 6362306a36Sopenharmony_ci "Hello world! This is an Efx loopback test in progress!"; 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_ci/* Interrupt mode names */ 6662306a36Sopenharmony_cistatic const unsigned int efx_siena_interrupt_mode_max = EFX_INT_MODE_MAX; 6762306a36Sopenharmony_cistatic const char *const efx_siena_interrupt_mode_names[] = { 6862306a36Sopenharmony_ci [EFX_INT_MODE_MSIX] = "MSI-X", 6962306a36Sopenharmony_ci [EFX_INT_MODE_MSI] = "MSI", 7062306a36Sopenharmony_ci [EFX_INT_MODE_LEGACY] = "legacy", 7162306a36Sopenharmony_ci}; 7262306a36Sopenharmony_ci#define INT_MODE(efx) \ 7362306a36Sopenharmony_ci STRING_TABLE_LOOKUP(efx->interrupt_mode, efx_siena_interrupt_mode) 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_ci/** 7662306a36Sopenharmony_ci * struct efx_loopback_state - persistent state during a loopback selftest 7762306a36Sopenharmony_ci * @flush: Drop all packets in efx_siena_loopback_rx_packet 7862306a36Sopenharmony_ci * @packet_count: Number of packets being used in this test 7962306a36Sopenharmony_ci * @skbs: An array of skbs transmitted 8062306a36Sopenharmony_ci * @offload_csum: Checksums are being offloaded 8162306a36Sopenharmony_ci * @rx_good: RX good packet count 8262306a36Sopenharmony_ci * @rx_bad: RX bad packet count 8362306a36Sopenharmony_ci * @payload: Payload used in tests 8462306a36Sopenharmony_ci */ 8562306a36Sopenharmony_cistruct efx_loopback_state { 8662306a36Sopenharmony_ci bool flush; 8762306a36Sopenharmony_ci int packet_count; 8862306a36Sopenharmony_ci struct sk_buff **skbs; 8962306a36Sopenharmony_ci bool offload_csum; 9062306a36Sopenharmony_ci atomic_t rx_good; 9162306a36Sopenharmony_ci atomic_t rx_bad; 9262306a36Sopenharmony_ci struct efx_loopback_payload payload; 9362306a36Sopenharmony_ci}; 9462306a36Sopenharmony_ci 9562306a36Sopenharmony_ci/* How long to wait for all the packets to arrive (in ms) */ 9662306a36Sopenharmony_ci#define LOOPBACK_TIMEOUT_MS 1000 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_ci/************************************************************************** 9962306a36Sopenharmony_ci * 10062306a36Sopenharmony_ci * MII, NVRAM and register tests 10162306a36Sopenharmony_ci * 10262306a36Sopenharmony_ci **************************************************************************/ 10362306a36Sopenharmony_ci 10462306a36Sopenharmony_cistatic int efx_test_phy_alive(struct efx_nic *efx, struct efx_self_tests *tests) 10562306a36Sopenharmony_ci{ 10662306a36Sopenharmony_ci int rc = 0; 10762306a36Sopenharmony_ci 10862306a36Sopenharmony_ci rc = efx_siena_mcdi_phy_test_alive(efx); 10962306a36Sopenharmony_ci tests->phy_alive = rc ? -1 : 1; 11062306a36Sopenharmony_ci 11162306a36Sopenharmony_ci return rc; 11262306a36Sopenharmony_ci} 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_cistatic int efx_test_nvram(struct efx_nic *efx, struct efx_self_tests *tests) 11562306a36Sopenharmony_ci{ 11662306a36Sopenharmony_ci int rc = 0; 11762306a36Sopenharmony_ci 11862306a36Sopenharmony_ci if (efx->type->test_nvram) { 11962306a36Sopenharmony_ci rc = efx->type->test_nvram(efx); 12062306a36Sopenharmony_ci if (rc == -EPERM) 12162306a36Sopenharmony_ci rc = 0; 12262306a36Sopenharmony_ci else 12362306a36Sopenharmony_ci tests->nvram = rc ? -1 : 1; 12462306a36Sopenharmony_ci } 12562306a36Sopenharmony_ci 12662306a36Sopenharmony_ci return rc; 12762306a36Sopenharmony_ci} 12862306a36Sopenharmony_ci 12962306a36Sopenharmony_ci/************************************************************************** 13062306a36Sopenharmony_ci * 13162306a36Sopenharmony_ci * Interrupt and event queue testing 13262306a36Sopenharmony_ci * 13362306a36Sopenharmony_ci **************************************************************************/ 13462306a36Sopenharmony_ci 13562306a36Sopenharmony_ci/* Test generation and receipt of interrupts */ 13662306a36Sopenharmony_cistatic int efx_test_interrupts(struct efx_nic *efx, 13762306a36Sopenharmony_ci struct efx_self_tests *tests) 13862306a36Sopenharmony_ci{ 13962306a36Sopenharmony_ci unsigned long timeout, wait; 14062306a36Sopenharmony_ci int cpu; 14162306a36Sopenharmony_ci int rc; 14262306a36Sopenharmony_ci 14362306a36Sopenharmony_ci netif_dbg(efx, drv, efx->net_dev, "testing interrupts\n"); 14462306a36Sopenharmony_ci tests->interrupt = -1; 14562306a36Sopenharmony_ci 14662306a36Sopenharmony_ci rc = efx_siena_irq_test_start(efx); 14762306a36Sopenharmony_ci if (rc == -ENOTSUPP) { 14862306a36Sopenharmony_ci netif_dbg(efx, drv, efx->net_dev, 14962306a36Sopenharmony_ci "direct interrupt testing not supported\n"); 15062306a36Sopenharmony_ci tests->interrupt = 0; 15162306a36Sopenharmony_ci return 0; 15262306a36Sopenharmony_ci } 15362306a36Sopenharmony_ci 15462306a36Sopenharmony_ci timeout = jiffies + IRQ_TIMEOUT; 15562306a36Sopenharmony_ci wait = 1; 15662306a36Sopenharmony_ci 15762306a36Sopenharmony_ci /* Wait for arrival of test interrupt. */ 15862306a36Sopenharmony_ci netif_dbg(efx, drv, efx->net_dev, "waiting for test interrupt\n"); 15962306a36Sopenharmony_ci do { 16062306a36Sopenharmony_ci schedule_timeout_uninterruptible(wait); 16162306a36Sopenharmony_ci cpu = efx_nic_irq_test_irq_cpu(efx); 16262306a36Sopenharmony_ci if (cpu >= 0) 16362306a36Sopenharmony_ci goto success; 16462306a36Sopenharmony_ci wait *= 2; 16562306a36Sopenharmony_ci } while (time_before(jiffies, timeout)); 16662306a36Sopenharmony_ci 16762306a36Sopenharmony_ci netif_err(efx, drv, efx->net_dev, "timed out waiting for interrupt\n"); 16862306a36Sopenharmony_ci return -ETIMEDOUT; 16962306a36Sopenharmony_ci 17062306a36Sopenharmony_ci success: 17162306a36Sopenharmony_ci netif_dbg(efx, drv, efx->net_dev, "%s test interrupt seen on CPU%d\n", 17262306a36Sopenharmony_ci INT_MODE(efx), cpu); 17362306a36Sopenharmony_ci tests->interrupt = 1; 17462306a36Sopenharmony_ci return 0; 17562306a36Sopenharmony_ci} 17662306a36Sopenharmony_ci 17762306a36Sopenharmony_ci/* Test generation and receipt of interrupting events */ 17862306a36Sopenharmony_cistatic int efx_test_eventq_irq(struct efx_nic *efx, 17962306a36Sopenharmony_ci struct efx_self_tests *tests) 18062306a36Sopenharmony_ci{ 18162306a36Sopenharmony_ci struct efx_channel *channel; 18262306a36Sopenharmony_ci unsigned int read_ptr[EFX_MAX_CHANNELS]; 18362306a36Sopenharmony_ci unsigned long napi_ran = 0, dma_pend = 0, int_pend = 0; 18462306a36Sopenharmony_ci unsigned long timeout, wait; 18562306a36Sopenharmony_ci 18662306a36Sopenharmony_ci BUILD_BUG_ON(EFX_MAX_CHANNELS > BITS_PER_LONG); 18762306a36Sopenharmony_ci 18862306a36Sopenharmony_ci efx_for_each_channel(channel, efx) { 18962306a36Sopenharmony_ci read_ptr[channel->channel] = channel->eventq_read_ptr; 19062306a36Sopenharmony_ci set_bit(channel->channel, &dma_pend); 19162306a36Sopenharmony_ci set_bit(channel->channel, &int_pend); 19262306a36Sopenharmony_ci efx_siena_event_test_start(channel); 19362306a36Sopenharmony_ci } 19462306a36Sopenharmony_ci 19562306a36Sopenharmony_ci timeout = jiffies + IRQ_TIMEOUT; 19662306a36Sopenharmony_ci wait = 1; 19762306a36Sopenharmony_ci 19862306a36Sopenharmony_ci /* Wait for arrival of interrupts. NAPI processing may or may 19962306a36Sopenharmony_ci * not complete in time, but we can cope in any case. 20062306a36Sopenharmony_ci */ 20162306a36Sopenharmony_ci do { 20262306a36Sopenharmony_ci schedule_timeout_uninterruptible(wait); 20362306a36Sopenharmony_ci 20462306a36Sopenharmony_ci efx_for_each_channel(channel, efx) { 20562306a36Sopenharmony_ci efx_siena_stop_eventq(channel); 20662306a36Sopenharmony_ci if (channel->eventq_read_ptr != 20762306a36Sopenharmony_ci read_ptr[channel->channel]) { 20862306a36Sopenharmony_ci set_bit(channel->channel, &napi_ran); 20962306a36Sopenharmony_ci clear_bit(channel->channel, &dma_pend); 21062306a36Sopenharmony_ci clear_bit(channel->channel, &int_pend); 21162306a36Sopenharmony_ci } else { 21262306a36Sopenharmony_ci if (efx_siena_event_present(channel)) 21362306a36Sopenharmony_ci clear_bit(channel->channel, &dma_pend); 21462306a36Sopenharmony_ci if (efx_nic_event_test_irq_cpu(channel) >= 0) 21562306a36Sopenharmony_ci clear_bit(channel->channel, &int_pend); 21662306a36Sopenharmony_ci } 21762306a36Sopenharmony_ci efx_siena_start_eventq(channel); 21862306a36Sopenharmony_ci } 21962306a36Sopenharmony_ci 22062306a36Sopenharmony_ci wait *= 2; 22162306a36Sopenharmony_ci } while ((dma_pend || int_pend) && time_before(jiffies, timeout)); 22262306a36Sopenharmony_ci 22362306a36Sopenharmony_ci efx_for_each_channel(channel, efx) { 22462306a36Sopenharmony_ci bool dma_seen = !test_bit(channel->channel, &dma_pend); 22562306a36Sopenharmony_ci bool int_seen = !test_bit(channel->channel, &int_pend); 22662306a36Sopenharmony_ci 22762306a36Sopenharmony_ci tests->eventq_dma[channel->channel] = dma_seen ? 1 : -1; 22862306a36Sopenharmony_ci tests->eventq_int[channel->channel] = int_seen ? 1 : -1; 22962306a36Sopenharmony_ci 23062306a36Sopenharmony_ci if (dma_seen && int_seen) { 23162306a36Sopenharmony_ci netif_dbg(efx, drv, efx->net_dev, 23262306a36Sopenharmony_ci "channel %d event queue passed (with%s NAPI)\n", 23362306a36Sopenharmony_ci channel->channel, 23462306a36Sopenharmony_ci test_bit(channel->channel, &napi_ran) ? 23562306a36Sopenharmony_ci "" : "out"); 23662306a36Sopenharmony_ci } else { 23762306a36Sopenharmony_ci /* Report failure and whether either interrupt or DMA 23862306a36Sopenharmony_ci * worked 23962306a36Sopenharmony_ci */ 24062306a36Sopenharmony_ci netif_err(efx, drv, efx->net_dev, 24162306a36Sopenharmony_ci "channel %d timed out waiting for event queue\n", 24262306a36Sopenharmony_ci channel->channel); 24362306a36Sopenharmony_ci if (int_seen) 24462306a36Sopenharmony_ci netif_err(efx, drv, efx->net_dev, 24562306a36Sopenharmony_ci "channel %d saw interrupt " 24662306a36Sopenharmony_ci "during event queue test\n", 24762306a36Sopenharmony_ci channel->channel); 24862306a36Sopenharmony_ci if (dma_seen) 24962306a36Sopenharmony_ci netif_err(efx, drv, efx->net_dev, 25062306a36Sopenharmony_ci "channel %d event was generated, but " 25162306a36Sopenharmony_ci "failed to trigger an interrupt\n", 25262306a36Sopenharmony_ci channel->channel); 25362306a36Sopenharmony_ci } 25462306a36Sopenharmony_ci } 25562306a36Sopenharmony_ci 25662306a36Sopenharmony_ci return (dma_pend || int_pend) ? -ETIMEDOUT : 0; 25762306a36Sopenharmony_ci} 25862306a36Sopenharmony_ci 25962306a36Sopenharmony_cistatic int efx_test_phy(struct efx_nic *efx, struct efx_self_tests *tests, 26062306a36Sopenharmony_ci unsigned flags) 26162306a36Sopenharmony_ci{ 26262306a36Sopenharmony_ci int rc; 26362306a36Sopenharmony_ci 26462306a36Sopenharmony_ci mutex_lock(&efx->mac_lock); 26562306a36Sopenharmony_ci rc = efx_siena_mcdi_phy_run_tests(efx, tests->phy_ext, flags); 26662306a36Sopenharmony_ci mutex_unlock(&efx->mac_lock); 26762306a36Sopenharmony_ci if (rc == -EPERM) 26862306a36Sopenharmony_ci rc = 0; 26962306a36Sopenharmony_ci else 27062306a36Sopenharmony_ci netif_info(efx, drv, efx->net_dev, 27162306a36Sopenharmony_ci "%s phy selftest\n", rc ? "Failed" : "Passed"); 27262306a36Sopenharmony_ci 27362306a36Sopenharmony_ci return rc; 27462306a36Sopenharmony_ci} 27562306a36Sopenharmony_ci 27662306a36Sopenharmony_ci/************************************************************************** 27762306a36Sopenharmony_ci * 27862306a36Sopenharmony_ci * Loopback testing 27962306a36Sopenharmony_ci * NB Only one loopback test can be executing concurrently. 28062306a36Sopenharmony_ci * 28162306a36Sopenharmony_ci **************************************************************************/ 28262306a36Sopenharmony_ci 28362306a36Sopenharmony_ci/* Loopback test RX callback 28462306a36Sopenharmony_ci * This is called for each received packet during loopback testing. 28562306a36Sopenharmony_ci */ 28662306a36Sopenharmony_civoid efx_siena_loopback_rx_packet(struct efx_nic *efx, 28762306a36Sopenharmony_ci const char *buf_ptr, int pkt_len) 28862306a36Sopenharmony_ci{ 28962306a36Sopenharmony_ci struct efx_loopback_state *state = efx->loopback_selftest; 29062306a36Sopenharmony_ci struct efx_loopback_payload received; 29162306a36Sopenharmony_ci struct efx_loopback_payload *payload; 29262306a36Sopenharmony_ci 29362306a36Sopenharmony_ci BUG_ON(!buf_ptr); 29462306a36Sopenharmony_ci 29562306a36Sopenharmony_ci /* If we are just flushing, then drop the packet */ 29662306a36Sopenharmony_ci if ((state == NULL) || state->flush) 29762306a36Sopenharmony_ci return; 29862306a36Sopenharmony_ci 29962306a36Sopenharmony_ci payload = &state->payload; 30062306a36Sopenharmony_ci 30162306a36Sopenharmony_ci memcpy(&received.packet, buf_ptr, 30262306a36Sopenharmony_ci min_t(int, pkt_len, EFX_LOOPBACK_PAYLOAD_LEN)); 30362306a36Sopenharmony_ci received.ip.saddr = payload->ip.saddr; 30462306a36Sopenharmony_ci if (state->offload_csum) 30562306a36Sopenharmony_ci received.ip.check = payload->ip.check; 30662306a36Sopenharmony_ci 30762306a36Sopenharmony_ci /* Check that header exists */ 30862306a36Sopenharmony_ci if (pkt_len < sizeof(received.header)) { 30962306a36Sopenharmony_ci netif_err(efx, drv, efx->net_dev, 31062306a36Sopenharmony_ci "saw runt RX packet (length %d) in %s loopback " 31162306a36Sopenharmony_ci "test\n", pkt_len, LOOPBACK_MODE(efx)); 31262306a36Sopenharmony_ci goto err; 31362306a36Sopenharmony_ci } 31462306a36Sopenharmony_ci 31562306a36Sopenharmony_ci /* Check that the ethernet header exists */ 31662306a36Sopenharmony_ci if (memcmp(&received.header, &payload->header, ETH_HLEN) != 0) { 31762306a36Sopenharmony_ci netif_err(efx, drv, efx->net_dev, 31862306a36Sopenharmony_ci "saw non-loopback RX packet in %s loopback test\n", 31962306a36Sopenharmony_ci LOOPBACK_MODE(efx)); 32062306a36Sopenharmony_ci goto err; 32162306a36Sopenharmony_ci } 32262306a36Sopenharmony_ci 32362306a36Sopenharmony_ci /* Check packet length */ 32462306a36Sopenharmony_ci if (pkt_len != EFX_LOOPBACK_PAYLOAD_LEN) { 32562306a36Sopenharmony_ci netif_err(efx, drv, efx->net_dev, 32662306a36Sopenharmony_ci "saw incorrect RX packet length %d (wanted %d) in " 32762306a36Sopenharmony_ci "%s loopback test\n", pkt_len, 32862306a36Sopenharmony_ci (int)EFX_LOOPBACK_PAYLOAD_LEN, LOOPBACK_MODE(efx)); 32962306a36Sopenharmony_ci goto err; 33062306a36Sopenharmony_ci } 33162306a36Sopenharmony_ci 33262306a36Sopenharmony_ci /* Check that IP header matches */ 33362306a36Sopenharmony_ci if (memcmp(&received.ip, &payload->ip, sizeof(payload->ip)) != 0) { 33462306a36Sopenharmony_ci netif_err(efx, drv, efx->net_dev, 33562306a36Sopenharmony_ci "saw corrupted IP header in %s loopback test\n", 33662306a36Sopenharmony_ci LOOPBACK_MODE(efx)); 33762306a36Sopenharmony_ci goto err; 33862306a36Sopenharmony_ci } 33962306a36Sopenharmony_ci 34062306a36Sopenharmony_ci /* Check that msg and padding matches */ 34162306a36Sopenharmony_ci if (memcmp(&received.msg, &payload->msg, sizeof(received.msg)) != 0) { 34262306a36Sopenharmony_ci netif_err(efx, drv, efx->net_dev, 34362306a36Sopenharmony_ci "saw corrupted RX packet in %s loopback test\n", 34462306a36Sopenharmony_ci LOOPBACK_MODE(efx)); 34562306a36Sopenharmony_ci goto err; 34662306a36Sopenharmony_ci } 34762306a36Sopenharmony_ci 34862306a36Sopenharmony_ci /* Check that iteration matches */ 34962306a36Sopenharmony_ci if (received.iteration != payload->iteration) { 35062306a36Sopenharmony_ci netif_err(efx, drv, efx->net_dev, 35162306a36Sopenharmony_ci "saw RX packet from iteration %d (wanted %d) in " 35262306a36Sopenharmony_ci "%s loopback test\n", ntohs(received.iteration), 35362306a36Sopenharmony_ci ntohs(payload->iteration), LOOPBACK_MODE(efx)); 35462306a36Sopenharmony_ci goto err; 35562306a36Sopenharmony_ci } 35662306a36Sopenharmony_ci 35762306a36Sopenharmony_ci /* Increase correct RX count */ 35862306a36Sopenharmony_ci netif_vdbg(efx, drv, efx->net_dev, 35962306a36Sopenharmony_ci "got loopback RX in %s loopback test\n", LOOPBACK_MODE(efx)); 36062306a36Sopenharmony_ci 36162306a36Sopenharmony_ci atomic_inc(&state->rx_good); 36262306a36Sopenharmony_ci return; 36362306a36Sopenharmony_ci 36462306a36Sopenharmony_ci err: 36562306a36Sopenharmony_ci#ifdef DEBUG 36662306a36Sopenharmony_ci if (atomic_read(&state->rx_bad) == 0) { 36762306a36Sopenharmony_ci netif_err(efx, drv, efx->net_dev, "received packet:\n"); 36862306a36Sopenharmony_ci print_hex_dump(KERN_ERR, "", DUMP_PREFIX_OFFSET, 0x10, 1, 36962306a36Sopenharmony_ci buf_ptr, pkt_len, 0); 37062306a36Sopenharmony_ci netif_err(efx, drv, efx->net_dev, "expected packet:\n"); 37162306a36Sopenharmony_ci print_hex_dump(KERN_ERR, "", DUMP_PREFIX_OFFSET, 0x10, 1, 37262306a36Sopenharmony_ci &state->payload.packet, EFX_LOOPBACK_PAYLOAD_LEN, 37362306a36Sopenharmony_ci 0); 37462306a36Sopenharmony_ci } 37562306a36Sopenharmony_ci#endif 37662306a36Sopenharmony_ci atomic_inc(&state->rx_bad); 37762306a36Sopenharmony_ci} 37862306a36Sopenharmony_ci 37962306a36Sopenharmony_ci/* Initialise an efx_siena_selftest_state for a new iteration */ 38062306a36Sopenharmony_cistatic void efx_iterate_state(struct efx_nic *efx) 38162306a36Sopenharmony_ci{ 38262306a36Sopenharmony_ci struct efx_loopback_state *state = efx->loopback_selftest; 38362306a36Sopenharmony_ci struct net_device *net_dev = efx->net_dev; 38462306a36Sopenharmony_ci struct efx_loopback_payload *payload = &state->payload; 38562306a36Sopenharmony_ci 38662306a36Sopenharmony_ci /* Initialise the layerII header */ 38762306a36Sopenharmony_ci ether_addr_copy((u8 *)&payload->header.h_dest, net_dev->dev_addr); 38862306a36Sopenharmony_ci ether_addr_copy((u8 *)&payload->header.h_source, payload_source); 38962306a36Sopenharmony_ci payload->header.h_proto = htons(ETH_P_IP); 39062306a36Sopenharmony_ci 39162306a36Sopenharmony_ci /* saddr set later and used as incrementing count */ 39262306a36Sopenharmony_ci payload->ip.daddr = htonl(INADDR_LOOPBACK); 39362306a36Sopenharmony_ci payload->ip.ihl = 5; 39462306a36Sopenharmony_ci payload->ip.check = (__force __sum16) htons(0xdead); 39562306a36Sopenharmony_ci payload->ip.tot_len = htons(sizeof(*payload) - 39662306a36Sopenharmony_ci offsetof(struct efx_loopback_payload, ip)); 39762306a36Sopenharmony_ci payload->ip.version = IPVERSION; 39862306a36Sopenharmony_ci payload->ip.protocol = IPPROTO_UDP; 39962306a36Sopenharmony_ci 40062306a36Sopenharmony_ci /* Initialise udp header */ 40162306a36Sopenharmony_ci payload->udp.source = 0; 40262306a36Sopenharmony_ci payload->udp.len = htons(sizeof(*payload) - 40362306a36Sopenharmony_ci offsetof(struct efx_loopback_payload, udp)); 40462306a36Sopenharmony_ci payload->udp.check = 0; /* checksum ignored */ 40562306a36Sopenharmony_ci 40662306a36Sopenharmony_ci /* Fill out payload */ 40762306a36Sopenharmony_ci payload->iteration = htons(ntohs(payload->iteration) + 1); 40862306a36Sopenharmony_ci memcpy(&payload->msg, payload_msg, sizeof(payload_msg)); 40962306a36Sopenharmony_ci 41062306a36Sopenharmony_ci /* Fill out remaining state members */ 41162306a36Sopenharmony_ci atomic_set(&state->rx_good, 0); 41262306a36Sopenharmony_ci atomic_set(&state->rx_bad, 0); 41362306a36Sopenharmony_ci smp_wmb(); 41462306a36Sopenharmony_ci} 41562306a36Sopenharmony_ci 41662306a36Sopenharmony_cistatic int efx_begin_loopback(struct efx_tx_queue *tx_queue) 41762306a36Sopenharmony_ci{ 41862306a36Sopenharmony_ci struct efx_nic *efx = tx_queue->efx; 41962306a36Sopenharmony_ci struct efx_loopback_state *state = efx->loopback_selftest; 42062306a36Sopenharmony_ci struct efx_loopback_payload *payload; 42162306a36Sopenharmony_ci struct sk_buff *skb; 42262306a36Sopenharmony_ci int i; 42362306a36Sopenharmony_ci netdev_tx_t rc; 42462306a36Sopenharmony_ci 42562306a36Sopenharmony_ci /* Transmit N copies of buffer */ 42662306a36Sopenharmony_ci for (i = 0; i < state->packet_count; i++) { 42762306a36Sopenharmony_ci /* Allocate an skb, holding an extra reference for 42862306a36Sopenharmony_ci * transmit completion counting */ 42962306a36Sopenharmony_ci skb = alloc_skb(sizeof(state->payload), GFP_KERNEL); 43062306a36Sopenharmony_ci if (!skb) 43162306a36Sopenharmony_ci return -ENOMEM; 43262306a36Sopenharmony_ci state->skbs[i] = skb; 43362306a36Sopenharmony_ci skb_get(skb); 43462306a36Sopenharmony_ci 43562306a36Sopenharmony_ci /* Copy the payload in, incrementing the source address to 43662306a36Sopenharmony_ci * exercise the rss vectors */ 43762306a36Sopenharmony_ci payload = skb_put(skb, sizeof(state->payload)); 43862306a36Sopenharmony_ci memcpy(payload, &state->payload, sizeof(state->payload)); 43962306a36Sopenharmony_ci payload->ip.saddr = htonl(INADDR_LOOPBACK | (i << 2)); 44062306a36Sopenharmony_ci /* Strip off the leading padding */ 44162306a36Sopenharmony_ci skb_pull(skb, offsetof(struct efx_loopback_payload, header)); 44262306a36Sopenharmony_ci /* Strip off the trailing padding */ 44362306a36Sopenharmony_ci skb_trim(skb, EFX_LOOPBACK_PAYLOAD_LEN); 44462306a36Sopenharmony_ci 44562306a36Sopenharmony_ci /* Ensure everything we've written is visible to the 44662306a36Sopenharmony_ci * interrupt handler. */ 44762306a36Sopenharmony_ci smp_wmb(); 44862306a36Sopenharmony_ci 44962306a36Sopenharmony_ci netif_tx_lock_bh(efx->net_dev); 45062306a36Sopenharmony_ci rc = efx_enqueue_skb(tx_queue, skb); 45162306a36Sopenharmony_ci netif_tx_unlock_bh(efx->net_dev); 45262306a36Sopenharmony_ci 45362306a36Sopenharmony_ci if (rc != NETDEV_TX_OK) { 45462306a36Sopenharmony_ci netif_err(efx, drv, efx->net_dev, 45562306a36Sopenharmony_ci "TX queue %d could not transmit packet %d of " 45662306a36Sopenharmony_ci "%d in %s loopback test\n", tx_queue->label, 45762306a36Sopenharmony_ci i + 1, state->packet_count, 45862306a36Sopenharmony_ci LOOPBACK_MODE(efx)); 45962306a36Sopenharmony_ci 46062306a36Sopenharmony_ci /* Defer cleaning up the other skbs for the caller */ 46162306a36Sopenharmony_ci kfree_skb(skb); 46262306a36Sopenharmony_ci return -EPIPE; 46362306a36Sopenharmony_ci } 46462306a36Sopenharmony_ci } 46562306a36Sopenharmony_ci 46662306a36Sopenharmony_ci return 0; 46762306a36Sopenharmony_ci} 46862306a36Sopenharmony_ci 46962306a36Sopenharmony_cistatic int efx_poll_loopback(struct efx_nic *efx) 47062306a36Sopenharmony_ci{ 47162306a36Sopenharmony_ci struct efx_loopback_state *state = efx->loopback_selftest; 47262306a36Sopenharmony_ci 47362306a36Sopenharmony_ci return atomic_read(&state->rx_good) == state->packet_count; 47462306a36Sopenharmony_ci} 47562306a36Sopenharmony_ci 47662306a36Sopenharmony_cistatic int efx_end_loopback(struct efx_tx_queue *tx_queue, 47762306a36Sopenharmony_ci struct efx_loopback_self_tests *lb_tests) 47862306a36Sopenharmony_ci{ 47962306a36Sopenharmony_ci struct efx_nic *efx = tx_queue->efx; 48062306a36Sopenharmony_ci struct efx_loopback_state *state = efx->loopback_selftest; 48162306a36Sopenharmony_ci struct sk_buff *skb; 48262306a36Sopenharmony_ci int tx_done = 0, rx_good, rx_bad; 48362306a36Sopenharmony_ci int i, rc = 0; 48462306a36Sopenharmony_ci 48562306a36Sopenharmony_ci netif_tx_lock_bh(efx->net_dev); 48662306a36Sopenharmony_ci 48762306a36Sopenharmony_ci /* Count the number of tx completions, and decrement the refcnt. Any 48862306a36Sopenharmony_ci * skbs not already completed will be free'd when the queue is flushed */ 48962306a36Sopenharmony_ci for (i = 0; i < state->packet_count; i++) { 49062306a36Sopenharmony_ci skb = state->skbs[i]; 49162306a36Sopenharmony_ci if (skb && !skb_shared(skb)) 49262306a36Sopenharmony_ci ++tx_done; 49362306a36Sopenharmony_ci dev_kfree_skb(skb); 49462306a36Sopenharmony_ci } 49562306a36Sopenharmony_ci 49662306a36Sopenharmony_ci netif_tx_unlock_bh(efx->net_dev); 49762306a36Sopenharmony_ci 49862306a36Sopenharmony_ci /* Check TX completion and received packet counts */ 49962306a36Sopenharmony_ci rx_good = atomic_read(&state->rx_good); 50062306a36Sopenharmony_ci rx_bad = atomic_read(&state->rx_bad); 50162306a36Sopenharmony_ci if (tx_done != state->packet_count) { 50262306a36Sopenharmony_ci /* Don't free the skbs; they will be picked up on TX 50362306a36Sopenharmony_ci * overflow or channel teardown. 50462306a36Sopenharmony_ci */ 50562306a36Sopenharmony_ci netif_err(efx, drv, efx->net_dev, 50662306a36Sopenharmony_ci "TX queue %d saw only %d out of an expected %d " 50762306a36Sopenharmony_ci "TX completion events in %s loopback test\n", 50862306a36Sopenharmony_ci tx_queue->label, tx_done, state->packet_count, 50962306a36Sopenharmony_ci LOOPBACK_MODE(efx)); 51062306a36Sopenharmony_ci rc = -ETIMEDOUT; 51162306a36Sopenharmony_ci /* Allow to fall through so we see the RX errors as well */ 51262306a36Sopenharmony_ci } 51362306a36Sopenharmony_ci 51462306a36Sopenharmony_ci /* We may always be up to a flush away from our desired packet total */ 51562306a36Sopenharmony_ci if (rx_good != state->packet_count) { 51662306a36Sopenharmony_ci netif_dbg(efx, drv, efx->net_dev, 51762306a36Sopenharmony_ci "TX queue %d saw only %d out of an expected %d " 51862306a36Sopenharmony_ci "received packets in %s loopback test\n", 51962306a36Sopenharmony_ci tx_queue->label, rx_good, state->packet_count, 52062306a36Sopenharmony_ci LOOPBACK_MODE(efx)); 52162306a36Sopenharmony_ci rc = -ETIMEDOUT; 52262306a36Sopenharmony_ci /* Fall through */ 52362306a36Sopenharmony_ci } 52462306a36Sopenharmony_ci 52562306a36Sopenharmony_ci /* Update loopback test structure */ 52662306a36Sopenharmony_ci lb_tests->tx_sent[tx_queue->label] += state->packet_count; 52762306a36Sopenharmony_ci lb_tests->tx_done[tx_queue->label] += tx_done; 52862306a36Sopenharmony_ci lb_tests->rx_good += rx_good; 52962306a36Sopenharmony_ci lb_tests->rx_bad += rx_bad; 53062306a36Sopenharmony_ci 53162306a36Sopenharmony_ci return rc; 53262306a36Sopenharmony_ci} 53362306a36Sopenharmony_ci 53462306a36Sopenharmony_cistatic int 53562306a36Sopenharmony_ciefx_test_loopback(struct efx_tx_queue *tx_queue, 53662306a36Sopenharmony_ci struct efx_loopback_self_tests *lb_tests) 53762306a36Sopenharmony_ci{ 53862306a36Sopenharmony_ci struct efx_nic *efx = tx_queue->efx; 53962306a36Sopenharmony_ci struct efx_loopback_state *state = efx->loopback_selftest; 54062306a36Sopenharmony_ci int i, begin_rc, end_rc; 54162306a36Sopenharmony_ci 54262306a36Sopenharmony_ci for (i = 0; i < 3; i++) { 54362306a36Sopenharmony_ci /* Determine how many packets to send */ 54462306a36Sopenharmony_ci state->packet_count = efx->txq_entries / 3; 54562306a36Sopenharmony_ci state->packet_count = min(1 << (i << 2), state->packet_count); 54662306a36Sopenharmony_ci state->skbs = kcalloc(state->packet_count, 54762306a36Sopenharmony_ci sizeof(state->skbs[0]), GFP_KERNEL); 54862306a36Sopenharmony_ci if (!state->skbs) 54962306a36Sopenharmony_ci return -ENOMEM; 55062306a36Sopenharmony_ci state->flush = false; 55162306a36Sopenharmony_ci 55262306a36Sopenharmony_ci netif_dbg(efx, drv, efx->net_dev, 55362306a36Sopenharmony_ci "TX queue %d (hw %d) testing %s loopback with %d packets\n", 55462306a36Sopenharmony_ci tx_queue->label, tx_queue->queue, LOOPBACK_MODE(efx), 55562306a36Sopenharmony_ci state->packet_count); 55662306a36Sopenharmony_ci 55762306a36Sopenharmony_ci efx_iterate_state(efx); 55862306a36Sopenharmony_ci begin_rc = efx_begin_loopback(tx_queue); 55962306a36Sopenharmony_ci 56062306a36Sopenharmony_ci /* This will normally complete very quickly, but be 56162306a36Sopenharmony_ci * prepared to wait much longer. */ 56262306a36Sopenharmony_ci msleep(1); 56362306a36Sopenharmony_ci if (!efx_poll_loopback(efx)) { 56462306a36Sopenharmony_ci msleep(LOOPBACK_TIMEOUT_MS); 56562306a36Sopenharmony_ci efx_poll_loopback(efx); 56662306a36Sopenharmony_ci } 56762306a36Sopenharmony_ci 56862306a36Sopenharmony_ci end_rc = efx_end_loopback(tx_queue, lb_tests); 56962306a36Sopenharmony_ci kfree(state->skbs); 57062306a36Sopenharmony_ci 57162306a36Sopenharmony_ci if (begin_rc || end_rc) { 57262306a36Sopenharmony_ci /* Wait a while to ensure there are no packets 57362306a36Sopenharmony_ci * floating around after a failure. */ 57462306a36Sopenharmony_ci schedule_timeout_uninterruptible(HZ / 10); 57562306a36Sopenharmony_ci return begin_rc ? begin_rc : end_rc; 57662306a36Sopenharmony_ci } 57762306a36Sopenharmony_ci } 57862306a36Sopenharmony_ci 57962306a36Sopenharmony_ci netif_dbg(efx, drv, efx->net_dev, 58062306a36Sopenharmony_ci "TX queue %d passed %s loopback test with a burst length " 58162306a36Sopenharmony_ci "of %d packets\n", tx_queue->label, LOOPBACK_MODE(efx), 58262306a36Sopenharmony_ci state->packet_count); 58362306a36Sopenharmony_ci 58462306a36Sopenharmony_ci return 0; 58562306a36Sopenharmony_ci} 58662306a36Sopenharmony_ci 58762306a36Sopenharmony_ci/* Wait for link up. On Falcon, we would prefer to rely on efx_monitor, but 58862306a36Sopenharmony_ci * any contention on the mac lock (via e.g. efx_mac_mcast_work) causes it 58962306a36Sopenharmony_ci * to delay and retry. Therefore, it's safer to just poll directly. Wait 59062306a36Sopenharmony_ci * for link up and any faults to dissipate. */ 59162306a36Sopenharmony_cistatic int efx_wait_for_link(struct efx_nic *efx) 59262306a36Sopenharmony_ci{ 59362306a36Sopenharmony_ci struct efx_link_state *link_state = &efx->link_state; 59462306a36Sopenharmony_ci int count, link_up_count = 0; 59562306a36Sopenharmony_ci bool link_up; 59662306a36Sopenharmony_ci 59762306a36Sopenharmony_ci for (count = 0; count < 40; count++) { 59862306a36Sopenharmony_ci schedule_timeout_uninterruptible(HZ / 10); 59962306a36Sopenharmony_ci 60062306a36Sopenharmony_ci if (efx->type->monitor != NULL) { 60162306a36Sopenharmony_ci mutex_lock(&efx->mac_lock); 60262306a36Sopenharmony_ci efx->type->monitor(efx); 60362306a36Sopenharmony_ci mutex_unlock(&efx->mac_lock); 60462306a36Sopenharmony_ci } 60562306a36Sopenharmony_ci 60662306a36Sopenharmony_ci mutex_lock(&efx->mac_lock); 60762306a36Sopenharmony_ci link_up = link_state->up; 60862306a36Sopenharmony_ci if (link_up) 60962306a36Sopenharmony_ci link_up = !efx->type->check_mac_fault(efx); 61062306a36Sopenharmony_ci mutex_unlock(&efx->mac_lock); 61162306a36Sopenharmony_ci 61262306a36Sopenharmony_ci if (link_up) { 61362306a36Sopenharmony_ci if (++link_up_count == 2) 61462306a36Sopenharmony_ci return 0; 61562306a36Sopenharmony_ci } else { 61662306a36Sopenharmony_ci link_up_count = 0; 61762306a36Sopenharmony_ci } 61862306a36Sopenharmony_ci } 61962306a36Sopenharmony_ci 62062306a36Sopenharmony_ci return -ETIMEDOUT; 62162306a36Sopenharmony_ci} 62262306a36Sopenharmony_ci 62362306a36Sopenharmony_cistatic int efx_test_loopbacks(struct efx_nic *efx, struct efx_self_tests *tests, 62462306a36Sopenharmony_ci unsigned int loopback_modes) 62562306a36Sopenharmony_ci{ 62662306a36Sopenharmony_ci enum efx_loopback_mode mode; 62762306a36Sopenharmony_ci struct efx_loopback_state *state; 62862306a36Sopenharmony_ci struct efx_channel *channel = 62962306a36Sopenharmony_ci efx_get_channel(efx, efx->tx_channel_offset); 63062306a36Sopenharmony_ci struct efx_tx_queue *tx_queue; 63162306a36Sopenharmony_ci int rc = 0; 63262306a36Sopenharmony_ci 63362306a36Sopenharmony_ci /* Set the port loopback_selftest member. From this point on 63462306a36Sopenharmony_ci * all received packets will be dropped. Mark the state as 63562306a36Sopenharmony_ci * "flushing" so all inflight packets are dropped */ 63662306a36Sopenharmony_ci state = kzalloc(sizeof(*state), GFP_KERNEL); 63762306a36Sopenharmony_ci if (state == NULL) 63862306a36Sopenharmony_ci return -ENOMEM; 63962306a36Sopenharmony_ci BUG_ON(efx->loopback_selftest); 64062306a36Sopenharmony_ci state->flush = true; 64162306a36Sopenharmony_ci efx->loopback_selftest = state; 64262306a36Sopenharmony_ci 64362306a36Sopenharmony_ci /* Test all supported loopback modes */ 64462306a36Sopenharmony_ci for (mode = LOOPBACK_NONE; mode <= LOOPBACK_TEST_MAX; mode++) { 64562306a36Sopenharmony_ci if (!(loopback_modes & (1 << mode))) 64662306a36Sopenharmony_ci continue; 64762306a36Sopenharmony_ci 64862306a36Sopenharmony_ci /* Move the port into the specified loopback mode. */ 64962306a36Sopenharmony_ci state->flush = true; 65062306a36Sopenharmony_ci mutex_lock(&efx->mac_lock); 65162306a36Sopenharmony_ci efx->loopback_mode = mode; 65262306a36Sopenharmony_ci rc = __efx_siena_reconfigure_port(efx); 65362306a36Sopenharmony_ci mutex_unlock(&efx->mac_lock); 65462306a36Sopenharmony_ci if (rc) { 65562306a36Sopenharmony_ci netif_err(efx, drv, efx->net_dev, 65662306a36Sopenharmony_ci "unable to move into %s loopback\n", 65762306a36Sopenharmony_ci LOOPBACK_MODE(efx)); 65862306a36Sopenharmony_ci goto out; 65962306a36Sopenharmony_ci } 66062306a36Sopenharmony_ci 66162306a36Sopenharmony_ci rc = efx_wait_for_link(efx); 66262306a36Sopenharmony_ci if (rc) { 66362306a36Sopenharmony_ci netif_err(efx, drv, efx->net_dev, 66462306a36Sopenharmony_ci "loopback %s never came up\n", 66562306a36Sopenharmony_ci LOOPBACK_MODE(efx)); 66662306a36Sopenharmony_ci goto out; 66762306a36Sopenharmony_ci } 66862306a36Sopenharmony_ci 66962306a36Sopenharmony_ci /* Test all enabled types of TX queue */ 67062306a36Sopenharmony_ci efx_for_each_channel_tx_queue(tx_queue, channel) { 67162306a36Sopenharmony_ci state->offload_csum = (tx_queue->type & 67262306a36Sopenharmony_ci EFX_TXQ_TYPE_OUTER_CSUM); 67362306a36Sopenharmony_ci rc = efx_test_loopback(tx_queue, 67462306a36Sopenharmony_ci &tests->loopback[mode]); 67562306a36Sopenharmony_ci if (rc) 67662306a36Sopenharmony_ci goto out; 67762306a36Sopenharmony_ci } 67862306a36Sopenharmony_ci } 67962306a36Sopenharmony_ci 68062306a36Sopenharmony_ci out: 68162306a36Sopenharmony_ci /* Remove the flush. The caller will remove the loopback setting */ 68262306a36Sopenharmony_ci state->flush = true; 68362306a36Sopenharmony_ci efx->loopback_selftest = NULL; 68462306a36Sopenharmony_ci wmb(); 68562306a36Sopenharmony_ci kfree(state); 68662306a36Sopenharmony_ci 68762306a36Sopenharmony_ci if (rc == -EPERM) 68862306a36Sopenharmony_ci rc = 0; 68962306a36Sopenharmony_ci 69062306a36Sopenharmony_ci return rc; 69162306a36Sopenharmony_ci} 69262306a36Sopenharmony_ci 69362306a36Sopenharmony_ci/************************************************************************** 69462306a36Sopenharmony_ci * 69562306a36Sopenharmony_ci * Entry point 69662306a36Sopenharmony_ci * 69762306a36Sopenharmony_ci *************************************************************************/ 69862306a36Sopenharmony_ci 69962306a36Sopenharmony_ciint efx_siena_selftest(struct efx_nic *efx, struct efx_self_tests *tests, 70062306a36Sopenharmony_ci unsigned int flags) 70162306a36Sopenharmony_ci{ 70262306a36Sopenharmony_ci enum efx_loopback_mode loopback_mode = efx->loopback_mode; 70362306a36Sopenharmony_ci int phy_mode = efx->phy_mode; 70462306a36Sopenharmony_ci int rc_test = 0, rc_reset, rc; 70562306a36Sopenharmony_ci 70662306a36Sopenharmony_ci efx_siena_selftest_async_cancel(efx); 70762306a36Sopenharmony_ci 70862306a36Sopenharmony_ci /* Online (i.e. non-disruptive) testing 70962306a36Sopenharmony_ci * This checks interrupt generation, event delivery and PHY presence. */ 71062306a36Sopenharmony_ci 71162306a36Sopenharmony_ci rc = efx_test_phy_alive(efx, tests); 71262306a36Sopenharmony_ci if (rc && !rc_test) 71362306a36Sopenharmony_ci rc_test = rc; 71462306a36Sopenharmony_ci 71562306a36Sopenharmony_ci rc = efx_test_nvram(efx, tests); 71662306a36Sopenharmony_ci if (rc && !rc_test) 71762306a36Sopenharmony_ci rc_test = rc; 71862306a36Sopenharmony_ci 71962306a36Sopenharmony_ci rc = efx_test_interrupts(efx, tests); 72062306a36Sopenharmony_ci if (rc && !rc_test) 72162306a36Sopenharmony_ci rc_test = rc; 72262306a36Sopenharmony_ci 72362306a36Sopenharmony_ci rc = efx_test_eventq_irq(efx, tests); 72462306a36Sopenharmony_ci if (rc && !rc_test) 72562306a36Sopenharmony_ci rc_test = rc; 72662306a36Sopenharmony_ci 72762306a36Sopenharmony_ci if (rc_test) 72862306a36Sopenharmony_ci return rc_test; 72962306a36Sopenharmony_ci 73062306a36Sopenharmony_ci if (!(flags & ETH_TEST_FL_OFFLINE)) 73162306a36Sopenharmony_ci return efx_test_phy(efx, tests, flags); 73262306a36Sopenharmony_ci 73362306a36Sopenharmony_ci /* Offline (i.e. disruptive) testing 73462306a36Sopenharmony_ci * This checks MAC and PHY loopback on the specified port. */ 73562306a36Sopenharmony_ci 73662306a36Sopenharmony_ci /* Detach the device so the kernel doesn't transmit during the 73762306a36Sopenharmony_ci * loopback test and the watchdog timeout doesn't fire. 73862306a36Sopenharmony_ci */ 73962306a36Sopenharmony_ci efx_device_detach_sync(efx); 74062306a36Sopenharmony_ci 74162306a36Sopenharmony_ci if (efx->type->test_chip) { 74262306a36Sopenharmony_ci rc_reset = efx->type->test_chip(efx, tests); 74362306a36Sopenharmony_ci if (rc_reset) { 74462306a36Sopenharmony_ci netif_err(efx, hw, efx->net_dev, 74562306a36Sopenharmony_ci "Unable to recover from chip test\n"); 74662306a36Sopenharmony_ci efx_siena_schedule_reset(efx, RESET_TYPE_DISABLE); 74762306a36Sopenharmony_ci return rc_reset; 74862306a36Sopenharmony_ci } 74962306a36Sopenharmony_ci 75062306a36Sopenharmony_ci if ((tests->memory < 0 || tests->registers < 0) && !rc_test) 75162306a36Sopenharmony_ci rc_test = -EIO; 75262306a36Sopenharmony_ci } 75362306a36Sopenharmony_ci 75462306a36Sopenharmony_ci /* Ensure that the phy is powered and out of loopback 75562306a36Sopenharmony_ci * for the bist and loopback tests */ 75662306a36Sopenharmony_ci mutex_lock(&efx->mac_lock); 75762306a36Sopenharmony_ci efx->phy_mode &= ~PHY_MODE_LOW_POWER; 75862306a36Sopenharmony_ci efx->loopback_mode = LOOPBACK_NONE; 75962306a36Sopenharmony_ci __efx_siena_reconfigure_port(efx); 76062306a36Sopenharmony_ci mutex_unlock(&efx->mac_lock); 76162306a36Sopenharmony_ci 76262306a36Sopenharmony_ci rc = efx_test_phy(efx, tests, flags); 76362306a36Sopenharmony_ci if (rc && !rc_test) 76462306a36Sopenharmony_ci rc_test = rc; 76562306a36Sopenharmony_ci 76662306a36Sopenharmony_ci rc = efx_test_loopbacks(efx, tests, efx->loopback_modes); 76762306a36Sopenharmony_ci if (rc && !rc_test) 76862306a36Sopenharmony_ci rc_test = rc; 76962306a36Sopenharmony_ci 77062306a36Sopenharmony_ci /* restore the PHY to the previous state */ 77162306a36Sopenharmony_ci mutex_lock(&efx->mac_lock); 77262306a36Sopenharmony_ci efx->phy_mode = phy_mode; 77362306a36Sopenharmony_ci efx->loopback_mode = loopback_mode; 77462306a36Sopenharmony_ci __efx_siena_reconfigure_port(efx); 77562306a36Sopenharmony_ci mutex_unlock(&efx->mac_lock); 77662306a36Sopenharmony_ci 77762306a36Sopenharmony_ci efx_device_attach_if_not_resetting(efx); 77862306a36Sopenharmony_ci 77962306a36Sopenharmony_ci return rc_test; 78062306a36Sopenharmony_ci} 78162306a36Sopenharmony_ci 78262306a36Sopenharmony_civoid efx_siena_selftest_async_start(struct efx_nic *efx) 78362306a36Sopenharmony_ci{ 78462306a36Sopenharmony_ci struct efx_channel *channel; 78562306a36Sopenharmony_ci 78662306a36Sopenharmony_ci efx_for_each_channel(channel, efx) 78762306a36Sopenharmony_ci efx_siena_event_test_start(channel); 78862306a36Sopenharmony_ci schedule_delayed_work(&efx->selftest_work, IRQ_TIMEOUT); 78962306a36Sopenharmony_ci} 79062306a36Sopenharmony_ci 79162306a36Sopenharmony_civoid efx_siena_selftest_async_cancel(struct efx_nic *efx) 79262306a36Sopenharmony_ci{ 79362306a36Sopenharmony_ci cancel_delayed_work_sync(&efx->selftest_work); 79462306a36Sopenharmony_ci} 79562306a36Sopenharmony_ci 79662306a36Sopenharmony_cistatic void efx_siena_selftest_async_work(struct work_struct *data) 79762306a36Sopenharmony_ci{ 79862306a36Sopenharmony_ci struct efx_nic *efx = container_of(data, struct efx_nic, 79962306a36Sopenharmony_ci selftest_work.work); 80062306a36Sopenharmony_ci struct efx_channel *channel; 80162306a36Sopenharmony_ci int cpu; 80262306a36Sopenharmony_ci 80362306a36Sopenharmony_ci efx_for_each_channel(channel, efx) { 80462306a36Sopenharmony_ci cpu = efx_nic_event_test_irq_cpu(channel); 80562306a36Sopenharmony_ci if (cpu < 0) 80662306a36Sopenharmony_ci netif_err(efx, ifup, efx->net_dev, 80762306a36Sopenharmony_ci "channel %d failed to trigger an interrupt\n", 80862306a36Sopenharmony_ci channel->channel); 80962306a36Sopenharmony_ci else 81062306a36Sopenharmony_ci netif_dbg(efx, ifup, efx->net_dev, 81162306a36Sopenharmony_ci "channel %d triggered interrupt on CPU %d\n", 81262306a36Sopenharmony_ci channel->channel, cpu); 81362306a36Sopenharmony_ci } 81462306a36Sopenharmony_ci} 81562306a36Sopenharmony_ci 81662306a36Sopenharmony_civoid efx_siena_selftest_async_init(struct efx_nic *efx) 81762306a36Sopenharmony_ci{ 81862306a36Sopenharmony_ci INIT_DELAYED_WORK(&efx->selftest_work, efx_siena_selftest_async_work); 81962306a36Sopenharmony_ci} 820