1d48523cbSMartin Habets // SPDX-License-Identifier: GPL-2.0-only 2d48523cbSMartin Habets /**************************************************************************** 3d48523cbSMartin Habets * Driver for Solarflare network controllers and boards 4d48523cbSMartin Habets * Copyright 2005-2006 Fen Systems Ltd. 5d48523cbSMartin Habets * Copyright 2006-2012 Solarflare Communications Inc. 6d48523cbSMartin Habets */ 7d48523cbSMartin Habets 8d48523cbSMartin Habets #include <linux/netdevice.h> 9d48523cbSMartin Habets #include <linux/module.h> 10d48523cbSMartin Habets #include <linux/delay.h> 11d48523cbSMartin Habets #include <linux/kernel_stat.h> 12d48523cbSMartin Habets #include <linux/pci.h> 13d48523cbSMartin Habets #include <linux/ethtool.h> 14d48523cbSMartin Habets #include <linux/ip.h> 15d48523cbSMartin Habets #include <linux/in.h> 16d48523cbSMartin Habets #include <linux/udp.h> 17d48523cbSMartin Habets #include <linux/rtnetlink.h> 18d48523cbSMartin Habets #include <linux/slab.h> 19d48523cbSMartin Habets #include "net_driver.h" 20d48523cbSMartin Habets #include "efx.h" 21d48523cbSMartin Habets #include "efx_common.h" 22d48523cbSMartin Habets #include "efx_channels.h" 23d48523cbSMartin Habets #include "nic.h" 24d48523cbSMartin Habets #include "mcdi_port_common.h" 25d48523cbSMartin Habets #include "selftest.h" 26d48523cbSMartin Habets #include "workarounds.h" 27d48523cbSMartin Habets 28d48523cbSMartin Habets /* IRQ latency can be enormous because: 29d48523cbSMartin Habets * - All IRQs may be disabled on a CPU for a *long* time by e.g. a 30d48523cbSMartin Habets * slow serial console or an old IDE driver doing error recovery 31d48523cbSMartin Habets * - The PREEMPT_RT patches mostly deal with this, but also allow a 32d48523cbSMartin Habets * tasklet or normal task to be given higher priority than our IRQ 33d48523cbSMartin Habets * threads 34d48523cbSMartin Habets * Try to avoid blaming the hardware for this. 35d48523cbSMartin Habets */ 36d48523cbSMartin Habets #define IRQ_TIMEOUT HZ 37d48523cbSMartin Habets 38d48523cbSMartin Habets /* 39d48523cbSMartin Habets * Loopback test packet structure 40d48523cbSMartin Habets * 41d48523cbSMartin Habets * The self-test should stress every RSS vector, and unfortunately 42d48523cbSMartin Habets * Falcon only performs RSS on TCP/UDP packets. 43d48523cbSMartin Habets */ 44d48523cbSMartin Habets struct efx_loopback_payload { 45*30c24dd8SEdward Cree char pad[2]; /* Ensures ip is 4-byte aligned */ 46d48523cbSMartin Habets struct ethhdr header; 47d48523cbSMartin Habets struct iphdr ip; 48d48523cbSMartin Habets struct udphdr udp; 49d48523cbSMartin Habets __be16 iteration; 50d48523cbSMartin Habets char msg[64]; 51*30c24dd8SEdward Cree } __packed __aligned(4); 52*30c24dd8SEdward Cree #define EFX_LOOPBACK_PAYLOAD_LEN (sizeof(struct efx_loopback_payload) - \ 53*30c24dd8SEdward Cree offsetof(struct efx_loopback_payload, \ 54*30c24dd8SEdward Cree header)) 55d48523cbSMartin Habets 56d48523cbSMartin Habets /* Loopback test source MAC address */ 57d48523cbSMartin Habets static const u8 payload_source[ETH_ALEN] __aligned(2) = { 58d48523cbSMartin Habets 0x00, 0x0f, 0x53, 0x1b, 0x1b, 0x1b, 59d48523cbSMartin Habets }; 60d48523cbSMartin Habets 61d48523cbSMartin Habets static const char payload_msg[] = 62d48523cbSMartin Habets "Hello world! This is an Efx loopback test in progress!"; 63d48523cbSMartin Habets 64d48523cbSMartin Habets /* Interrupt mode names */ 6571ad88f6SMartin Habets static const unsigned int efx_siena_interrupt_mode_max = EFX_INT_MODE_MAX; 6671ad88f6SMartin Habets static const char *const efx_siena_interrupt_mode_names[] = { 67d48523cbSMartin Habets [EFX_INT_MODE_MSIX] = "MSI-X", 68d48523cbSMartin Habets [EFX_INT_MODE_MSI] = "MSI", 69d48523cbSMartin Habets [EFX_INT_MODE_LEGACY] = "legacy", 70d48523cbSMartin Habets }; 71d48523cbSMartin Habets #define INT_MODE(efx) \ 7271ad88f6SMartin Habets STRING_TABLE_LOOKUP(efx->interrupt_mode, efx_siena_interrupt_mode) 73d48523cbSMartin Habets 74d48523cbSMartin Habets /** 75d48523cbSMartin Habets * struct efx_loopback_state - persistent state during a loopback selftest 7695e96f77SMartin Habets * @flush: Drop all packets in efx_siena_loopback_rx_packet 77d48523cbSMartin Habets * @packet_count: Number of packets being used in this test 78d48523cbSMartin Habets * @skbs: An array of skbs transmitted 79d48523cbSMartin Habets * @offload_csum: Checksums are being offloaded 80d48523cbSMartin Habets * @rx_good: RX good packet count 81d48523cbSMartin Habets * @rx_bad: RX bad packet count 82d48523cbSMartin Habets * @payload: Payload used in tests 83d48523cbSMartin Habets */ 84d48523cbSMartin Habets struct efx_loopback_state { 85d48523cbSMartin Habets bool flush; 86d48523cbSMartin Habets int packet_count; 87d48523cbSMartin Habets struct sk_buff **skbs; 88d48523cbSMartin Habets bool offload_csum; 89d48523cbSMartin Habets atomic_t rx_good; 90d48523cbSMartin Habets atomic_t rx_bad; 91d48523cbSMartin Habets struct efx_loopback_payload payload; 92d48523cbSMartin Habets }; 93d48523cbSMartin Habets 94d48523cbSMartin Habets /* How long to wait for all the packets to arrive (in ms) */ 95d48523cbSMartin Habets #define LOOPBACK_TIMEOUT_MS 1000 96d48523cbSMartin Habets 97d48523cbSMartin Habets /************************************************************************** 98d48523cbSMartin Habets * 99d48523cbSMartin Habets * MII, NVRAM and register tests 100d48523cbSMartin Habets * 101d48523cbSMartin Habets **************************************************************************/ 102d48523cbSMartin Habets 103d48523cbSMartin Habets static int efx_test_phy_alive(struct efx_nic *efx, struct efx_self_tests *tests) 104d48523cbSMartin Habets { 105d48523cbSMartin Habets int rc = 0; 106d48523cbSMartin Habets 1074d49e5cdSMartin Habets rc = efx_siena_mcdi_phy_test_alive(efx); 108d48523cbSMartin Habets tests->phy_alive = rc ? -1 : 1; 109d48523cbSMartin Habets 110d48523cbSMartin Habets return rc; 111d48523cbSMartin Habets } 112d48523cbSMartin Habets 113d48523cbSMartin Habets static int efx_test_nvram(struct efx_nic *efx, struct efx_self_tests *tests) 114d48523cbSMartin Habets { 115d48523cbSMartin Habets int rc = 0; 116d48523cbSMartin Habets 117d48523cbSMartin Habets if (efx->type->test_nvram) { 118d48523cbSMartin Habets rc = efx->type->test_nvram(efx); 119d48523cbSMartin Habets if (rc == -EPERM) 120d48523cbSMartin Habets rc = 0; 121d48523cbSMartin Habets else 122d48523cbSMartin Habets tests->nvram = rc ? -1 : 1; 123d48523cbSMartin Habets } 124d48523cbSMartin Habets 125d48523cbSMartin Habets return rc; 126d48523cbSMartin Habets } 127d48523cbSMartin Habets 128d48523cbSMartin Habets /************************************************************************** 129d48523cbSMartin Habets * 130d48523cbSMartin Habets * Interrupt and event queue testing 131d48523cbSMartin Habets * 132d48523cbSMartin Habets **************************************************************************/ 133d48523cbSMartin Habets 134d48523cbSMartin Habets /* Test generation and receipt of interrupts */ 135d48523cbSMartin Habets static int efx_test_interrupts(struct efx_nic *efx, 136d48523cbSMartin Habets struct efx_self_tests *tests) 137d48523cbSMartin Habets { 138d48523cbSMartin Habets unsigned long timeout, wait; 139d48523cbSMartin Habets int cpu; 140d48523cbSMartin Habets int rc; 141d48523cbSMartin Habets 142d48523cbSMartin Habets netif_dbg(efx, drv, efx->net_dev, "testing interrupts\n"); 143d48523cbSMartin Habets tests->interrupt = -1; 144d48523cbSMartin Habets 145c8443b69SMartin Habets rc = efx_siena_irq_test_start(efx); 146d48523cbSMartin Habets if (rc == -ENOTSUPP) { 147d48523cbSMartin Habets netif_dbg(efx, drv, efx->net_dev, 148d48523cbSMartin Habets "direct interrupt testing not supported\n"); 149d48523cbSMartin Habets tests->interrupt = 0; 150d48523cbSMartin Habets return 0; 151d48523cbSMartin Habets } 152d48523cbSMartin Habets 153d48523cbSMartin Habets timeout = jiffies + IRQ_TIMEOUT; 154d48523cbSMartin Habets wait = 1; 155d48523cbSMartin Habets 156d48523cbSMartin Habets /* Wait for arrival of test interrupt. */ 157d48523cbSMartin Habets netif_dbg(efx, drv, efx->net_dev, "waiting for test interrupt\n"); 158d48523cbSMartin Habets do { 159d48523cbSMartin Habets schedule_timeout_uninterruptible(wait); 160d48523cbSMartin Habets cpu = efx_nic_irq_test_irq_cpu(efx); 161d48523cbSMartin Habets if (cpu >= 0) 162d48523cbSMartin Habets goto success; 163d48523cbSMartin Habets wait *= 2; 164d48523cbSMartin Habets } while (time_before(jiffies, timeout)); 165d48523cbSMartin Habets 166d48523cbSMartin Habets netif_err(efx, drv, efx->net_dev, "timed out waiting for interrupt\n"); 167d48523cbSMartin Habets return -ETIMEDOUT; 168d48523cbSMartin Habets 169d48523cbSMartin Habets success: 170d48523cbSMartin Habets netif_dbg(efx, drv, efx->net_dev, "%s test interrupt seen on CPU%d\n", 171d48523cbSMartin Habets INT_MODE(efx), cpu); 172d48523cbSMartin Habets tests->interrupt = 1; 173d48523cbSMartin Habets return 0; 174d48523cbSMartin Habets } 175d48523cbSMartin Habets 176d48523cbSMartin Habets /* Test generation and receipt of interrupting events */ 177d48523cbSMartin Habets static int efx_test_eventq_irq(struct efx_nic *efx, 178d48523cbSMartin Habets struct efx_self_tests *tests) 179d48523cbSMartin Habets { 180d48523cbSMartin Habets struct efx_channel *channel; 181d48523cbSMartin Habets unsigned int read_ptr[EFX_MAX_CHANNELS]; 182d48523cbSMartin Habets unsigned long napi_ran = 0, dma_pend = 0, int_pend = 0; 183d48523cbSMartin Habets unsigned long timeout, wait; 184d48523cbSMartin Habets 185d48523cbSMartin Habets BUILD_BUG_ON(EFX_MAX_CHANNELS > BITS_PER_LONG); 186d48523cbSMartin Habets 187d48523cbSMartin Habets efx_for_each_channel(channel, efx) { 188d48523cbSMartin Habets read_ptr[channel->channel] = channel->eventq_read_ptr; 189d48523cbSMartin Habets set_bit(channel->channel, &dma_pend); 190d48523cbSMartin Habets set_bit(channel->channel, &int_pend); 191c8443b69SMartin Habets efx_siena_event_test_start(channel); 192d48523cbSMartin Habets } 193d48523cbSMartin Habets 194d48523cbSMartin Habets timeout = jiffies + IRQ_TIMEOUT; 195d48523cbSMartin Habets wait = 1; 196d48523cbSMartin Habets 197d48523cbSMartin Habets /* Wait for arrival of interrupts. NAPI processing may or may 198d48523cbSMartin Habets * not complete in time, but we can cope in any case. 199d48523cbSMartin Habets */ 200d48523cbSMartin Habets do { 201d48523cbSMartin Habets schedule_timeout_uninterruptible(wait); 202d48523cbSMartin Habets 203d48523cbSMartin Habets efx_for_each_channel(channel, efx) { 20471ad88f6SMartin Habets efx_siena_stop_eventq(channel); 205d48523cbSMartin Habets if (channel->eventq_read_ptr != 206d48523cbSMartin Habets read_ptr[channel->channel]) { 207d48523cbSMartin Habets set_bit(channel->channel, &napi_ran); 208d48523cbSMartin Habets clear_bit(channel->channel, &dma_pend); 209d48523cbSMartin Habets clear_bit(channel->channel, &int_pend); 210d48523cbSMartin Habets } else { 211c8443b69SMartin Habets if (efx_siena_event_present(channel)) 212d48523cbSMartin Habets clear_bit(channel->channel, &dma_pend); 213d48523cbSMartin Habets if (efx_nic_event_test_irq_cpu(channel) >= 0) 214d48523cbSMartin Habets clear_bit(channel->channel, &int_pend); 215d48523cbSMartin Habets } 21671ad88f6SMartin Habets efx_siena_start_eventq(channel); 217d48523cbSMartin Habets } 218d48523cbSMartin Habets 219d48523cbSMartin Habets wait *= 2; 220d48523cbSMartin Habets } while ((dma_pend || int_pend) && time_before(jiffies, timeout)); 221d48523cbSMartin Habets 222d48523cbSMartin Habets efx_for_each_channel(channel, efx) { 223d48523cbSMartin Habets bool dma_seen = !test_bit(channel->channel, &dma_pend); 224d48523cbSMartin Habets bool int_seen = !test_bit(channel->channel, &int_pend); 225d48523cbSMartin Habets 226d48523cbSMartin Habets tests->eventq_dma[channel->channel] = dma_seen ? 1 : -1; 227d48523cbSMartin Habets tests->eventq_int[channel->channel] = int_seen ? 1 : -1; 228d48523cbSMartin Habets 229d48523cbSMartin Habets if (dma_seen && int_seen) { 230d48523cbSMartin Habets netif_dbg(efx, drv, efx->net_dev, 231d48523cbSMartin Habets "channel %d event queue passed (with%s NAPI)\n", 232d48523cbSMartin Habets channel->channel, 233d48523cbSMartin Habets test_bit(channel->channel, &napi_ran) ? 234d48523cbSMartin Habets "" : "out"); 235d48523cbSMartin Habets } else { 236d48523cbSMartin Habets /* Report failure and whether either interrupt or DMA 237d48523cbSMartin Habets * worked 238d48523cbSMartin Habets */ 239d48523cbSMartin Habets netif_err(efx, drv, efx->net_dev, 240d48523cbSMartin Habets "channel %d timed out waiting for event queue\n", 241d48523cbSMartin Habets channel->channel); 242d48523cbSMartin Habets if (int_seen) 243d48523cbSMartin Habets netif_err(efx, drv, efx->net_dev, 244d48523cbSMartin Habets "channel %d saw interrupt " 245d48523cbSMartin Habets "during event queue test\n", 246d48523cbSMartin Habets channel->channel); 247d48523cbSMartin Habets if (dma_seen) 248d48523cbSMartin Habets netif_err(efx, drv, efx->net_dev, 249d48523cbSMartin Habets "channel %d event was generated, but " 250d48523cbSMartin Habets "failed to trigger an interrupt\n", 251d48523cbSMartin Habets channel->channel); 252d48523cbSMartin Habets } 253d48523cbSMartin Habets } 254d48523cbSMartin Habets 255d48523cbSMartin Habets return (dma_pend || int_pend) ? -ETIMEDOUT : 0; 256d48523cbSMartin Habets } 257d48523cbSMartin Habets 258d48523cbSMartin Habets static int efx_test_phy(struct efx_nic *efx, struct efx_self_tests *tests, 259d48523cbSMartin Habets unsigned flags) 260d48523cbSMartin Habets { 261d48523cbSMartin Habets int rc; 262d48523cbSMartin Habets 263d48523cbSMartin Habets mutex_lock(&efx->mac_lock); 2644d49e5cdSMartin Habets rc = efx_siena_mcdi_phy_run_tests(efx, tests->phy_ext, flags); 265d48523cbSMartin Habets mutex_unlock(&efx->mac_lock); 266d48523cbSMartin Habets if (rc == -EPERM) 267d48523cbSMartin Habets rc = 0; 268d48523cbSMartin Habets else 269d48523cbSMartin Habets netif_info(efx, drv, efx->net_dev, 270d48523cbSMartin Habets "%s phy selftest\n", rc ? "Failed" : "Passed"); 271d48523cbSMartin Habets 272d48523cbSMartin Habets return rc; 273d48523cbSMartin Habets } 274d48523cbSMartin Habets 275d48523cbSMartin Habets /************************************************************************** 276d48523cbSMartin Habets * 277d48523cbSMartin Habets * Loopback testing 278d48523cbSMartin Habets * NB Only one loopback test can be executing concurrently. 279d48523cbSMartin Habets * 280d48523cbSMartin Habets **************************************************************************/ 281d48523cbSMartin Habets 282d48523cbSMartin Habets /* Loopback test RX callback 283d48523cbSMartin Habets * This is called for each received packet during loopback testing. 284d48523cbSMartin Habets */ 28595e96f77SMartin Habets void efx_siena_loopback_rx_packet(struct efx_nic *efx, 286d48523cbSMartin Habets const char *buf_ptr, int pkt_len) 287d48523cbSMartin Habets { 288d48523cbSMartin Habets struct efx_loopback_state *state = efx->loopback_selftest; 289*30c24dd8SEdward Cree struct efx_loopback_payload received; 290d48523cbSMartin Habets struct efx_loopback_payload *payload; 291d48523cbSMartin Habets 292d48523cbSMartin Habets BUG_ON(!buf_ptr); 293d48523cbSMartin Habets 294d48523cbSMartin Habets /* If we are just flushing, then drop the packet */ 295d48523cbSMartin Habets if ((state == NULL) || state->flush) 296d48523cbSMartin Habets return; 297d48523cbSMartin Habets 298d48523cbSMartin Habets payload = &state->payload; 299d48523cbSMartin Habets 300*30c24dd8SEdward Cree memcpy(&received.header, buf_ptr, 301*30c24dd8SEdward Cree min_t(int, pkt_len, EFX_LOOPBACK_PAYLOAD_LEN)); 302*30c24dd8SEdward Cree received.ip.saddr = payload->ip.saddr; 303d48523cbSMartin Habets if (state->offload_csum) 304*30c24dd8SEdward Cree received.ip.check = payload->ip.check; 305d48523cbSMartin Habets 306d48523cbSMartin Habets /* Check that header exists */ 307*30c24dd8SEdward Cree if (pkt_len < sizeof(received.header)) { 308d48523cbSMartin Habets netif_err(efx, drv, efx->net_dev, 309d48523cbSMartin Habets "saw runt RX packet (length %d) in %s loopback " 310d48523cbSMartin Habets "test\n", pkt_len, LOOPBACK_MODE(efx)); 311d48523cbSMartin Habets goto err; 312d48523cbSMartin Habets } 313d48523cbSMartin Habets 314d48523cbSMartin Habets /* Check that the ethernet header exists */ 315*30c24dd8SEdward Cree if (memcmp(&received.header, &payload->header, ETH_HLEN) != 0) { 316d48523cbSMartin Habets netif_err(efx, drv, efx->net_dev, 317d48523cbSMartin Habets "saw non-loopback RX packet in %s loopback test\n", 318d48523cbSMartin Habets LOOPBACK_MODE(efx)); 319d48523cbSMartin Habets goto err; 320d48523cbSMartin Habets } 321d48523cbSMartin Habets 322d48523cbSMartin Habets /* Check packet length */ 323*30c24dd8SEdward Cree if (pkt_len != EFX_LOOPBACK_PAYLOAD_LEN) { 324d48523cbSMartin Habets netif_err(efx, drv, efx->net_dev, 325d48523cbSMartin Habets "saw incorrect RX packet length %d (wanted %d) in " 326*30c24dd8SEdward Cree "%s loopback test\n", pkt_len, 327*30c24dd8SEdward Cree (int)EFX_LOOPBACK_PAYLOAD_LEN, LOOPBACK_MODE(efx)); 328d48523cbSMartin Habets goto err; 329d48523cbSMartin Habets } 330d48523cbSMartin Habets 331d48523cbSMartin Habets /* Check that IP header matches */ 332*30c24dd8SEdward Cree if (memcmp(&received.ip, &payload->ip, sizeof(payload->ip)) != 0) { 333d48523cbSMartin Habets netif_err(efx, drv, efx->net_dev, 334d48523cbSMartin Habets "saw corrupted IP header in %s loopback test\n", 335d48523cbSMartin Habets LOOPBACK_MODE(efx)); 336d48523cbSMartin Habets goto err; 337d48523cbSMartin Habets } 338d48523cbSMartin Habets 339d48523cbSMartin Habets /* Check that msg and padding matches */ 340*30c24dd8SEdward Cree if (memcmp(&received.msg, &payload->msg, sizeof(received.msg)) != 0) { 341d48523cbSMartin Habets netif_err(efx, drv, efx->net_dev, 342d48523cbSMartin Habets "saw corrupted RX packet in %s loopback test\n", 343d48523cbSMartin Habets LOOPBACK_MODE(efx)); 344d48523cbSMartin Habets goto err; 345d48523cbSMartin Habets } 346d48523cbSMartin Habets 347d48523cbSMartin Habets /* Check that iteration matches */ 348*30c24dd8SEdward Cree if (received.iteration != payload->iteration) { 349d48523cbSMartin Habets netif_err(efx, drv, efx->net_dev, 350d48523cbSMartin Habets "saw RX packet from iteration %d (wanted %d) in " 351*30c24dd8SEdward Cree "%s loopback test\n", ntohs(received.iteration), 352d48523cbSMartin Habets ntohs(payload->iteration), LOOPBACK_MODE(efx)); 353d48523cbSMartin Habets goto err; 354d48523cbSMartin Habets } 355d48523cbSMartin Habets 356d48523cbSMartin Habets /* Increase correct RX count */ 357d48523cbSMartin Habets netif_vdbg(efx, drv, efx->net_dev, 358d48523cbSMartin Habets "got loopback RX in %s loopback test\n", LOOPBACK_MODE(efx)); 359d48523cbSMartin Habets 360d48523cbSMartin Habets atomic_inc(&state->rx_good); 361d48523cbSMartin Habets return; 362d48523cbSMartin Habets 363d48523cbSMartin Habets err: 364d48523cbSMartin Habets #ifdef DEBUG 365d48523cbSMartin Habets if (atomic_read(&state->rx_bad) == 0) { 366d48523cbSMartin Habets netif_err(efx, drv, efx->net_dev, "received packet:\n"); 367d48523cbSMartin Habets print_hex_dump(KERN_ERR, "", DUMP_PREFIX_OFFSET, 0x10, 1, 368d48523cbSMartin Habets buf_ptr, pkt_len, 0); 369d48523cbSMartin Habets netif_err(efx, drv, efx->net_dev, "expected packet:\n"); 370d48523cbSMartin Habets print_hex_dump(KERN_ERR, "", DUMP_PREFIX_OFFSET, 0x10, 1, 371*30c24dd8SEdward Cree &state->payload.header, EFX_LOOPBACK_PAYLOAD_LEN, 372*30c24dd8SEdward Cree 0); 373d48523cbSMartin Habets } 374d48523cbSMartin Habets #endif 375d48523cbSMartin Habets atomic_inc(&state->rx_bad); 376d48523cbSMartin Habets } 377d48523cbSMartin Habets 37895e96f77SMartin Habets /* Initialise an efx_siena_selftest_state for a new iteration */ 379d48523cbSMartin Habets static void efx_iterate_state(struct efx_nic *efx) 380d48523cbSMartin Habets { 381d48523cbSMartin Habets struct efx_loopback_state *state = efx->loopback_selftest; 382d48523cbSMartin Habets struct net_device *net_dev = efx->net_dev; 383d48523cbSMartin Habets struct efx_loopback_payload *payload = &state->payload; 384d48523cbSMartin Habets 385d48523cbSMartin Habets /* Initialise the layerII header */ 386d48523cbSMartin Habets ether_addr_copy((u8 *)&payload->header.h_dest, net_dev->dev_addr); 387d48523cbSMartin Habets ether_addr_copy((u8 *)&payload->header.h_source, payload_source); 388d48523cbSMartin Habets payload->header.h_proto = htons(ETH_P_IP); 389d48523cbSMartin Habets 390d48523cbSMartin Habets /* saddr set later and used as incrementing count */ 391d48523cbSMartin Habets payload->ip.daddr = htonl(INADDR_LOOPBACK); 392d48523cbSMartin Habets payload->ip.ihl = 5; 393d48523cbSMartin Habets payload->ip.check = (__force __sum16) htons(0xdead); 394*30c24dd8SEdward Cree payload->ip.tot_len = htons(sizeof(*payload) - 395*30c24dd8SEdward Cree offsetof(struct efx_loopback_payload, ip)); 396d48523cbSMartin Habets payload->ip.version = IPVERSION; 397d48523cbSMartin Habets payload->ip.protocol = IPPROTO_UDP; 398d48523cbSMartin Habets 399d48523cbSMartin Habets /* Initialise udp header */ 400d48523cbSMartin Habets payload->udp.source = 0; 401*30c24dd8SEdward Cree payload->udp.len = htons(sizeof(*payload) - 402*30c24dd8SEdward Cree offsetof(struct efx_loopback_payload, udp)); 403d48523cbSMartin Habets payload->udp.check = 0; /* checksum ignored */ 404d48523cbSMartin Habets 405d48523cbSMartin Habets /* Fill out payload */ 406d48523cbSMartin Habets payload->iteration = htons(ntohs(payload->iteration) + 1); 407d48523cbSMartin Habets memcpy(&payload->msg, payload_msg, sizeof(payload_msg)); 408d48523cbSMartin Habets 409d48523cbSMartin Habets /* Fill out remaining state members */ 410d48523cbSMartin Habets atomic_set(&state->rx_good, 0); 411d48523cbSMartin Habets atomic_set(&state->rx_bad, 0); 412d48523cbSMartin Habets smp_wmb(); 413d48523cbSMartin Habets } 414d48523cbSMartin Habets 415d48523cbSMartin Habets static int efx_begin_loopback(struct efx_tx_queue *tx_queue) 416d48523cbSMartin Habets { 417d48523cbSMartin Habets struct efx_nic *efx = tx_queue->efx; 418d48523cbSMartin Habets struct efx_loopback_state *state = efx->loopback_selftest; 419d48523cbSMartin Habets struct efx_loopback_payload *payload; 420d48523cbSMartin Habets struct sk_buff *skb; 421d48523cbSMartin Habets int i; 422d48523cbSMartin Habets netdev_tx_t rc; 423d48523cbSMartin Habets 424d48523cbSMartin Habets /* Transmit N copies of buffer */ 425d48523cbSMartin Habets for (i = 0; i < state->packet_count; i++) { 426d48523cbSMartin Habets /* Allocate an skb, holding an extra reference for 427d48523cbSMartin Habets * transmit completion counting */ 428*30c24dd8SEdward Cree skb = alloc_skb(EFX_LOOPBACK_PAYLOAD_LEN, GFP_KERNEL); 429d48523cbSMartin Habets if (!skb) 430d48523cbSMartin Habets return -ENOMEM; 431d48523cbSMartin Habets state->skbs[i] = skb; 432d48523cbSMartin Habets skb_get(skb); 433d48523cbSMartin Habets 434d48523cbSMartin Habets /* Copy the payload in, incrementing the source address to 435d48523cbSMartin Habets * exercise the rss vectors */ 436d48523cbSMartin Habets payload = skb_put(skb, sizeof(state->payload)); 437d48523cbSMartin Habets memcpy(payload, &state->payload, sizeof(state->payload)); 438d48523cbSMartin Habets payload->ip.saddr = htonl(INADDR_LOOPBACK | (i << 2)); 439*30c24dd8SEdward Cree /* Strip off the leading padding */ 440*30c24dd8SEdward Cree skb_pull(skb, offsetof(struct efx_loopback_payload, header)); 441d48523cbSMartin Habets 442d48523cbSMartin Habets /* Ensure everything we've written is visible to the 443d48523cbSMartin Habets * interrupt handler. */ 444d48523cbSMartin Habets smp_wmb(); 445d48523cbSMartin Habets 446d48523cbSMartin Habets netif_tx_lock_bh(efx->net_dev); 447d48523cbSMartin Habets rc = efx_enqueue_skb(tx_queue, skb); 448d48523cbSMartin Habets netif_tx_unlock_bh(efx->net_dev); 449d48523cbSMartin Habets 450d48523cbSMartin Habets if (rc != NETDEV_TX_OK) { 451d48523cbSMartin Habets netif_err(efx, drv, efx->net_dev, 452d48523cbSMartin Habets "TX queue %d could not transmit packet %d of " 453d48523cbSMartin Habets "%d in %s loopback test\n", tx_queue->label, 454d48523cbSMartin Habets i + 1, state->packet_count, 455d48523cbSMartin Habets LOOPBACK_MODE(efx)); 456d48523cbSMartin Habets 457d48523cbSMartin Habets /* Defer cleaning up the other skbs for the caller */ 458d48523cbSMartin Habets kfree_skb(skb); 459d48523cbSMartin Habets return -EPIPE; 460d48523cbSMartin Habets } 461d48523cbSMartin Habets } 462d48523cbSMartin Habets 463d48523cbSMartin Habets return 0; 464d48523cbSMartin Habets } 465d48523cbSMartin Habets 466d48523cbSMartin Habets static int efx_poll_loopback(struct efx_nic *efx) 467d48523cbSMartin Habets { 468d48523cbSMartin Habets struct efx_loopback_state *state = efx->loopback_selftest; 469d48523cbSMartin Habets 470d48523cbSMartin Habets return atomic_read(&state->rx_good) == state->packet_count; 471d48523cbSMartin Habets } 472d48523cbSMartin Habets 473d48523cbSMartin Habets static int efx_end_loopback(struct efx_tx_queue *tx_queue, 474d48523cbSMartin Habets struct efx_loopback_self_tests *lb_tests) 475d48523cbSMartin Habets { 476d48523cbSMartin Habets struct efx_nic *efx = tx_queue->efx; 477d48523cbSMartin Habets struct efx_loopback_state *state = efx->loopback_selftest; 478d48523cbSMartin Habets struct sk_buff *skb; 479d48523cbSMartin Habets int tx_done = 0, rx_good, rx_bad; 480d48523cbSMartin Habets int i, rc = 0; 481d48523cbSMartin Habets 482d48523cbSMartin Habets netif_tx_lock_bh(efx->net_dev); 483d48523cbSMartin Habets 484d48523cbSMartin Habets /* Count the number of tx completions, and decrement the refcnt. Any 485d48523cbSMartin Habets * skbs not already completed will be free'd when the queue is flushed */ 486d48523cbSMartin Habets for (i = 0; i < state->packet_count; i++) { 487d48523cbSMartin Habets skb = state->skbs[i]; 488d48523cbSMartin Habets if (skb && !skb_shared(skb)) 489d48523cbSMartin Habets ++tx_done; 490d48523cbSMartin Habets dev_kfree_skb(skb); 491d48523cbSMartin Habets } 492d48523cbSMartin Habets 493d48523cbSMartin Habets netif_tx_unlock_bh(efx->net_dev); 494d48523cbSMartin Habets 495d48523cbSMartin Habets /* Check TX completion and received packet counts */ 496d48523cbSMartin Habets rx_good = atomic_read(&state->rx_good); 497d48523cbSMartin Habets rx_bad = atomic_read(&state->rx_bad); 498d48523cbSMartin Habets if (tx_done != state->packet_count) { 499d48523cbSMartin Habets /* Don't free the skbs; they will be picked up on TX 500d48523cbSMartin Habets * overflow or channel teardown. 501d48523cbSMartin Habets */ 502d48523cbSMartin Habets netif_err(efx, drv, efx->net_dev, 503d48523cbSMartin Habets "TX queue %d saw only %d out of an expected %d " 504d48523cbSMartin Habets "TX completion events in %s loopback test\n", 505d48523cbSMartin Habets tx_queue->label, tx_done, state->packet_count, 506d48523cbSMartin Habets LOOPBACK_MODE(efx)); 507d48523cbSMartin Habets rc = -ETIMEDOUT; 508d48523cbSMartin Habets /* Allow to fall through so we see the RX errors as well */ 509d48523cbSMartin Habets } 510d48523cbSMartin Habets 511d48523cbSMartin Habets /* We may always be up to a flush away from our desired packet total */ 512d48523cbSMartin Habets if (rx_good != state->packet_count) { 513d48523cbSMartin Habets netif_dbg(efx, drv, efx->net_dev, 514d48523cbSMartin Habets "TX queue %d saw only %d out of an expected %d " 515d48523cbSMartin Habets "received packets in %s loopback test\n", 516d48523cbSMartin Habets tx_queue->label, rx_good, state->packet_count, 517d48523cbSMartin Habets LOOPBACK_MODE(efx)); 518d48523cbSMartin Habets rc = -ETIMEDOUT; 519d48523cbSMartin Habets /* Fall through */ 520d48523cbSMartin Habets } 521d48523cbSMartin Habets 522d48523cbSMartin Habets /* Update loopback test structure */ 523d48523cbSMartin Habets lb_tests->tx_sent[tx_queue->label] += state->packet_count; 524d48523cbSMartin Habets lb_tests->tx_done[tx_queue->label] += tx_done; 525d48523cbSMartin Habets lb_tests->rx_good += rx_good; 526d48523cbSMartin Habets lb_tests->rx_bad += rx_bad; 527d48523cbSMartin Habets 528d48523cbSMartin Habets return rc; 529d48523cbSMartin Habets } 530d48523cbSMartin Habets 531d48523cbSMartin Habets static int 532d48523cbSMartin Habets efx_test_loopback(struct efx_tx_queue *tx_queue, 533d48523cbSMartin Habets struct efx_loopback_self_tests *lb_tests) 534d48523cbSMartin Habets { 535d48523cbSMartin Habets struct efx_nic *efx = tx_queue->efx; 536d48523cbSMartin Habets struct efx_loopback_state *state = efx->loopback_selftest; 537d48523cbSMartin Habets int i, begin_rc, end_rc; 538d48523cbSMartin Habets 539d48523cbSMartin Habets for (i = 0; i < 3; i++) { 540d48523cbSMartin Habets /* Determine how many packets to send */ 541d48523cbSMartin Habets state->packet_count = efx->txq_entries / 3; 542d48523cbSMartin Habets state->packet_count = min(1 << (i << 2), state->packet_count); 543d48523cbSMartin Habets state->skbs = kcalloc(state->packet_count, 544d48523cbSMartin Habets sizeof(state->skbs[0]), GFP_KERNEL); 545d48523cbSMartin Habets if (!state->skbs) 546d48523cbSMartin Habets return -ENOMEM; 547d48523cbSMartin Habets state->flush = false; 548d48523cbSMartin Habets 549d48523cbSMartin Habets netif_dbg(efx, drv, efx->net_dev, 550d48523cbSMartin Habets "TX queue %d (hw %d) testing %s loopback with %d packets\n", 551d48523cbSMartin Habets tx_queue->label, tx_queue->queue, LOOPBACK_MODE(efx), 552d48523cbSMartin Habets state->packet_count); 553d48523cbSMartin Habets 554d48523cbSMartin Habets efx_iterate_state(efx); 555d48523cbSMartin Habets begin_rc = efx_begin_loopback(tx_queue); 556d48523cbSMartin Habets 557d48523cbSMartin Habets /* This will normally complete very quickly, but be 558d48523cbSMartin Habets * prepared to wait much longer. */ 559d48523cbSMartin Habets msleep(1); 560d48523cbSMartin Habets if (!efx_poll_loopback(efx)) { 561d48523cbSMartin Habets msleep(LOOPBACK_TIMEOUT_MS); 562d48523cbSMartin Habets efx_poll_loopback(efx); 563d48523cbSMartin Habets } 564d48523cbSMartin Habets 565d48523cbSMartin Habets end_rc = efx_end_loopback(tx_queue, lb_tests); 566d48523cbSMartin Habets kfree(state->skbs); 567d48523cbSMartin Habets 568d48523cbSMartin Habets if (begin_rc || end_rc) { 569d48523cbSMartin Habets /* Wait a while to ensure there are no packets 570d48523cbSMartin Habets * floating around after a failure. */ 571d48523cbSMartin Habets schedule_timeout_uninterruptible(HZ / 10); 572d48523cbSMartin Habets return begin_rc ? begin_rc : end_rc; 573d48523cbSMartin Habets } 574d48523cbSMartin Habets } 575d48523cbSMartin Habets 576d48523cbSMartin Habets netif_dbg(efx, drv, efx->net_dev, 577d48523cbSMartin Habets "TX queue %d passed %s loopback test with a burst length " 578d48523cbSMartin Habets "of %d packets\n", tx_queue->label, LOOPBACK_MODE(efx), 579d48523cbSMartin Habets state->packet_count); 580d48523cbSMartin Habets 581d48523cbSMartin Habets return 0; 582d48523cbSMartin Habets } 583d48523cbSMartin Habets 584d48523cbSMartin Habets /* Wait for link up. On Falcon, we would prefer to rely on efx_monitor, but 585d48523cbSMartin Habets * any contention on the mac lock (via e.g. efx_mac_mcast_work) causes it 586d48523cbSMartin Habets * to delay and retry. Therefore, it's safer to just poll directly. Wait 587d48523cbSMartin Habets * for link up and any faults to dissipate. */ 588d48523cbSMartin Habets static int efx_wait_for_link(struct efx_nic *efx) 589d48523cbSMartin Habets { 590d48523cbSMartin Habets struct efx_link_state *link_state = &efx->link_state; 591d48523cbSMartin Habets int count, link_up_count = 0; 592d48523cbSMartin Habets bool link_up; 593d48523cbSMartin Habets 594d48523cbSMartin Habets for (count = 0; count < 40; count++) { 595d48523cbSMartin Habets schedule_timeout_uninterruptible(HZ / 10); 596d48523cbSMartin Habets 597d48523cbSMartin Habets if (efx->type->monitor != NULL) { 598d48523cbSMartin Habets mutex_lock(&efx->mac_lock); 599d48523cbSMartin Habets efx->type->monitor(efx); 600d48523cbSMartin Habets mutex_unlock(&efx->mac_lock); 601d48523cbSMartin Habets } 602d48523cbSMartin Habets 603d48523cbSMartin Habets mutex_lock(&efx->mac_lock); 604d48523cbSMartin Habets link_up = link_state->up; 605d48523cbSMartin Habets if (link_up) 606d48523cbSMartin Habets link_up = !efx->type->check_mac_fault(efx); 607d48523cbSMartin Habets mutex_unlock(&efx->mac_lock); 608d48523cbSMartin Habets 609d48523cbSMartin Habets if (link_up) { 610d48523cbSMartin Habets if (++link_up_count == 2) 611d48523cbSMartin Habets return 0; 612d48523cbSMartin Habets } else { 613d48523cbSMartin Habets link_up_count = 0; 614d48523cbSMartin Habets } 615d48523cbSMartin Habets } 616d48523cbSMartin Habets 617d48523cbSMartin Habets return -ETIMEDOUT; 618d48523cbSMartin Habets } 619d48523cbSMartin Habets 620d48523cbSMartin Habets static int efx_test_loopbacks(struct efx_nic *efx, struct efx_self_tests *tests, 621d48523cbSMartin Habets unsigned int loopback_modes) 622d48523cbSMartin Habets { 623d48523cbSMartin Habets enum efx_loopback_mode mode; 624d48523cbSMartin Habets struct efx_loopback_state *state; 625d48523cbSMartin Habets struct efx_channel *channel = 626d48523cbSMartin Habets efx_get_channel(efx, efx->tx_channel_offset); 627d48523cbSMartin Habets struct efx_tx_queue *tx_queue; 628d48523cbSMartin Habets int rc = 0; 629d48523cbSMartin Habets 630d48523cbSMartin Habets /* Set the port loopback_selftest member. From this point on 631d48523cbSMartin Habets * all received packets will be dropped. Mark the state as 632d48523cbSMartin Habets * "flushing" so all inflight packets are dropped */ 633d48523cbSMartin Habets state = kzalloc(sizeof(*state), GFP_KERNEL); 634d48523cbSMartin Habets if (state == NULL) 635d48523cbSMartin Habets return -ENOMEM; 636d48523cbSMartin Habets BUG_ON(efx->loopback_selftest); 637d48523cbSMartin Habets state->flush = true; 638d48523cbSMartin Habets efx->loopback_selftest = state; 639d48523cbSMartin Habets 640d48523cbSMartin Habets /* Test all supported loopback modes */ 641d48523cbSMartin Habets for (mode = LOOPBACK_NONE; mode <= LOOPBACK_TEST_MAX; mode++) { 642d48523cbSMartin Habets if (!(loopback_modes & (1 << mode))) 643d48523cbSMartin Habets continue; 644d48523cbSMartin Habets 645d48523cbSMartin Habets /* Move the port into the specified loopback mode. */ 646d48523cbSMartin Habets state->flush = true; 647d48523cbSMartin Habets mutex_lock(&efx->mac_lock); 648d48523cbSMartin Habets efx->loopback_mode = mode; 64971ad88f6SMartin Habets rc = __efx_siena_reconfigure_port(efx); 650d48523cbSMartin Habets mutex_unlock(&efx->mac_lock); 651d48523cbSMartin Habets if (rc) { 652d48523cbSMartin Habets netif_err(efx, drv, efx->net_dev, 653d48523cbSMartin Habets "unable to move into %s loopback\n", 654d48523cbSMartin Habets LOOPBACK_MODE(efx)); 655d48523cbSMartin Habets goto out; 656d48523cbSMartin Habets } 657d48523cbSMartin Habets 658d48523cbSMartin Habets rc = efx_wait_for_link(efx); 659d48523cbSMartin Habets if (rc) { 660d48523cbSMartin Habets netif_err(efx, drv, efx->net_dev, 661d48523cbSMartin Habets "loopback %s never came up\n", 662d48523cbSMartin Habets LOOPBACK_MODE(efx)); 663d48523cbSMartin Habets goto out; 664d48523cbSMartin Habets } 665d48523cbSMartin Habets 666d48523cbSMartin Habets /* Test all enabled types of TX queue */ 667d48523cbSMartin Habets efx_for_each_channel_tx_queue(tx_queue, channel) { 668d48523cbSMartin Habets state->offload_csum = (tx_queue->type & 669d48523cbSMartin Habets EFX_TXQ_TYPE_OUTER_CSUM); 670d48523cbSMartin Habets rc = efx_test_loopback(tx_queue, 671d48523cbSMartin Habets &tests->loopback[mode]); 672d48523cbSMartin Habets if (rc) 673d48523cbSMartin Habets goto out; 674d48523cbSMartin Habets } 675d48523cbSMartin Habets } 676d48523cbSMartin Habets 677d48523cbSMartin Habets out: 678d48523cbSMartin Habets /* Remove the flush. The caller will remove the loopback setting */ 679d48523cbSMartin Habets state->flush = true; 680d48523cbSMartin Habets efx->loopback_selftest = NULL; 681d48523cbSMartin Habets wmb(); 682d48523cbSMartin Habets kfree(state); 683d48523cbSMartin Habets 684d48523cbSMartin Habets if (rc == -EPERM) 685d48523cbSMartin Habets rc = 0; 686d48523cbSMartin Habets 687d48523cbSMartin Habets return rc; 688d48523cbSMartin Habets } 689d48523cbSMartin Habets 690d48523cbSMartin Habets /************************************************************************** 691d48523cbSMartin Habets * 692d48523cbSMartin Habets * Entry point 693d48523cbSMartin Habets * 694d48523cbSMartin Habets *************************************************************************/ 695d48523cbSMartin Habets 69695e96f77SMartin Habets int efx_siena_selftest(struct efx_nic *efx, struct efx_self_tests *tests, 69795e96f77SMartin Habets unsigned int flags) 698d48523cbSMartin Habets { 699d48523cbSMartin Habets enum efx_loopback_mode loopback_mode = efx->loopback_mode; 700d48523cbSMartin Habets int phy_mode = efx->phy_mode; 701d48523cbSMartin Habets int rc_test = 0, rc_reset, rc; 702d48523cbSMartin Habets 70395e96f77SMartin Habets efx_siena_selftest_async_cancel(efx); 704d48523cbSMartin Habets 705d48523cbSMartin Habets /* Online (i.e. non-disruptive) testing 706d48523cbSMartin Habets * This checks interrupt generation, event delivery and PHY presence. */ 707d48523cbSMartin Habets 708d48523cbSMartin Habets rc = efx_test_phy_alive(efx, tests); 709d48523cbSMartin Habets if (rc && !rc_test) 710d48523cbSMartin Habets rc_test = rc; 711d48523cbSMartin Habets 712d48523cbSMartin Habets rc = efx_test_nvram(efx, tests); 713d48523cbSMartin Habets if (rc && !rc_test) 714d48523cbSMartin Habets rc_test = rc; 715d48523cbSMartin Habets 716d48523cbSMartin Habets rc = efx_test_interrupts(efx, tests); 717d48523cbSMartin Habets if (rc && !rc_test) 718d48523cbSMartin Habets rc_test = rc; 719d48523cbSMartin Habets 720d48523cbSMartin Habets rc = efx_test_eventq_irq(efx, tests); 721d48523cbSMartin Habets if (rc && !rc_test) 722d48523cbSMartin Habets rc_test = rc; 723d48523cbSMartin Habets 724d48523cbSMartin Habets if (rc_test) 725d48523cbSMartin Habets return rc_test; 726d48523cbSMartin Habets 727d48523cbSMartin Habets if (!(flags & ETH_TEST_FL_OFFLINE)) 728d48523cbSMartin Habets return efx_test_phy(efx, tests, flags); 729d48523cbSMartin Habets 730d48523cbSMartin Habets /* Offline (i.e. disruptive) testing 731d48523cbSMartin Habets * This checks MAC and PHY loopback on the specified port. */ 732d48523cbSMartin Habets 733d48523cbSMartin Habets /* Detach the device so the kernel doesn't transmit during the 734d48523cbSMartin Habets * loopback test and the watchdog timeout doesn't fire. 735d48523cbSMartin Habets */ 736d48523cbSMartin Habets efx_device_detach_sync(efx); 737d48523cbSMartin Habets 738d48523cbSMartin Habets if (efx->type->test_chip) { 739d48523cbSMartin Habets rc_reset = efx->type->test_chip(efx, tests); 740d48523cbSMartin Habets if (rc_reset) { 741d48523cbSMartin Habets netif_err(efx, hw, efx->net_dev, 742d48523cbSMartin Habets "Unable to recover from chip test\n"); 74371ad88f6SMartin Habets efx_siena_schedule_reset(efx, RESET_TYPE_DISABLE); 744d48523cbSMartin Habets return rc_reset; 745d48523cbSMartin Habets } 746d48523cbSMartin Habets 747d48523cbSMartin Habets if ((tests->memory < 0 || tests->registers < 0) && !rc_test) 748d48523cbSMartin Habets rc_test = -EIO; 749d48523cbSMartin Habets } 750d48523cbSMartin Habets 751d48523cbSMartin Habets /* Ensure that the phy is powered and out of loopback 752d48523cbSMartin Habets * for the bist and loopback tests */ 753d48523cbSMartin Habets mutex_lock(&efx->mac_lock); 754d48523cbSMartin Habets efx->phy_mode &= ~PHY_MODE_LOW_POWER; 755d48523cbSMartin Habets efx->loopback_mode = LOOPBACK_NONE; 75671ad88f6SMartin Habets __efx_siena_reconfigure_port(efx); 757d48523cbSMartin Habets mutex_unlock(&efx->mac_lock); 758d48523cbSMartin Habets 759d48523cbSMartin Habets rc = efx_test_phy(efx, tests, flags); 760d48523cbSMartin Habets if (rc && !rc_test) 761d48523cbSMartin Habets rc_test = rc; 762d48523cbSMartin Habets 763d48523cbSMartin Habets rc = efx_test_loopbacks(efx, tests, efx->loopback_modes); 764d48523cbSMartin Habets if (rc && !rc_test) 765d48523cbSMartin Habets rc_test = rc; 766d48523cbSMartin Habets 767d48523cbSMartin Habets /* restore the PHY to the previous state */ 768d48523cbSMartin Habets mutex_lock(&efx->mac_lock); 769d48523cbSMartin Habets efx->phy_mode = phy_mode; 770d48523cbSMartin Habets efx->loopback_mode = loopback_mode; 77171ad88f6SMartin Habets __efx_siena_reconfigure_port(efx); 772d48523cbSMartin Habets mutex_unlock(&efx->mac_lock); 773d48523cbSMartin Habets 774d48523cbSMartin Habets efx_device_attach_if_not_resetting(efx); 775d48523cbSMartin Habets 776d48523cbSMartin Habets return rc_test; 777d48523cbSMartin Habets } 778d48523cbSMartin Habets 77995e96f77SMartin Habets void efx_siena_selftest_async_start(struct efx_nic *efx) 780d48523cbSMartin Habets { 781d48523cbSMartin Habets struct efx_channel *channel; 782d48523cbSMartin Habets 783d48523cbSMartin Habets efx_for_each_channel(channel, efx) 784c8443b69SMartin Habets efx_siena_event_test_start(channel); 785d48523cbSMartin Habets schedule_delayed_work(&efx->selftest_work, IRQ_TIMEOUT); 786d48523cbSMartin Habets } 787d48523cbSMartin Habets 78895e96f77SMartin Habets void efx_siena_selftest_async_cancel(struct efx_nic *efx) 789d48523cbSMartin Habets { 790d48523cbSMartin Habets cancel_delayed_work_sync(&efx->selftest_work); 791d48523cbSMartin Habets } 792d48523cbSMartin Habets 79395e96f77SMartin Habets static void efx_siena_selftest_async_work(struct work_struct *data) 794d48523cbSMartin Habets { 795d48523cbSMartin Habets struct efx_nic *efx = container_of(data, struct efx_nic, 796d48523cbSMartin Habets selftest_work.work); 797d48523cbSMartin Habets struct efx_channel *channel; 798d48523cbSMartin Habets int cpu; 799d48523cbSMartin Habets 800d48523cbSMartin Habets efx_for_each_channel(channel, efx) { 801d48523cbSMartin Habets cpu = efx_nic_event_test_irq_cpu(channel); 802d48523cbSMartin Habets if (cpu < 0) 803d48523cbSMartin Habets netif_err(efx, ifup, efx->net_dev, 804d48523cbSMartin Habets "channel %d failed to trigger an interrupt\n", 805d48523cbSMartin Habets channel->channel); 806d48523cbSMartin Habets else 807d48523cbSMartin Habets netif_dbg(efx, ifup, efx->net_dev, 808d48523cbSMartin Habets "channel %d triggered interrupt on CPU %d\n", 809d48523cbSMartin Habets channel->channel, cpu); 810d48523cbSMartin Habets } 811d48523cbSMartin Habets } 812d48523cbSMartin Habets 81395e96f77SMartin Habets void efx_siena_selftest_async_init(struct efx_nic *efx) 814d48523cbSMartin Habets { 81595e96f77SMartin Habets INIT_DELAYED_WORK(&efx->selftest_work, efx_siena_selftest_async_work); 816d48523cbSMartin Habets } 817