| .. | .. |
|---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
|---|
| 1 | 2 | /**************************************************************************** |
|---|
| 2 | 3 | * Driver for Solarflare network controllers and boards |
|---|
| 3 | 4 | * Copyright 2005-2006 Fen Systems Ltd. |
|---|
| 4 | 5 | * Copyright 2006-2013 Solarflare Communications Inc. |
|---|
| 5 | | - * |
|---|
| 6 | | - * This program is free software; you can redistribute it and/or modify it |
|---|
| 7 | | - * under the terms of the GNU General Public License version 2 as published |
|---|
| 8 | | - * by the Free Software Foundation, incorporated herein by reference. |
|---|
| 9 | 6 | */ |
|---|
| 10 | 7 | |
|---|
| 11 | 8 | #include <linux/bitops.h> |
|---|
| .. | .. |
|---|
| 23 | 20 | #include "farch_regs.h" |
|---|
| 24 | 21 | #include "io.h" |
|---|
| 25 | 22 | #include "workarounds.h" |
|---|
| 23 | +#include "mcdi_pcol.h" |
|---|
| 26 | 24 | |
|---|
| 27 | 25 | /************************************************************************** |
|---|
| 28 | 26 | * |
|---|
| .. | .. |
|---|
| 34 | 32 | int efx_nic_alloc_buffer(struct efx_nic *efx, struct efx_buffer *buffer, |
|---|
| 35 | 33 | unsigned int len, gfp_t gfp_flags) |
|---|
| 36 | 34 | { |
|---|
| 37 | | - buffer->addr = dma_zalloc_coherent(&efx->pci_dev->dev, len, |
|---|
| 38 | | - &buffer->dma_addr, gfp_flags); |
|---|
| 35 | + buffer->addr = dma_alloc_coherent(&efx->pci_dev->dev, len, |
|---|
| 36 | + &buffer->dma_addr, gfp_flags); |
|---|
| 39 | 37 | if (!buffer->addr) |
|---|
| 40 | 38 | return -ENOMEM; |
|---|
| 41 | 39 | buffer->len = len; |
|---|
| .. | .. |
|---|
| 92 | 90 | efx->pci_dev->irq); |
|---|
| 93 | 91 | goto fail1; |
|---|
| 94 | 92 | } |
|---|
| 93 | + efx->irqs_hooked = true; |
|---|
| 95 | 94 | return 0; |
|---|
| 96 | 95 | } |
|---|
| 97 | 96 | |
|---|
| .. | .. |
|---|
| 131 | 130 | #endif |
|---|
| 132 | 131 | } |
|---|
| 133 | 132 | |
|---|
| 133 | + efx->irqs_hooked = true; |
|---|
| 134 | 134 | return 0; |
|---|
| 135 | 135 | |
|---|
| 136 | 136 | fail2: |
|---|
| .. | .. |
|---|
| 156 | 156 | efx->net_dev->rx_cpu_rmap = NULL; |
|---|
| 157 | 157 | #endif |
|---|
| 158 | 158 | |
|---|
| 159 | + if (!efx->irqs_hooked) |
|---|
| 160 | + return; |
|---|
| 159 | 161 | if (EFX_INT_MODE_USE_MSI(efx)) { |
|---|
| 160 | 162 | /* Disable MSI/MSI-X interrupts */ |
|---|
| 161 | 163 | efx_for_each_channel(channel, efx) |
|---|
| .. | .. |
|---|
| 165 | 167 | /* Disable legacy interrupt */ |
|---|
| 166 | 168 | free_irq(efx->legacy_irq, efx); |
|---|
| 167 | 169 | } |
|---|
| 170 | + efx->irqs_hooked = false; |
|---|
| 168 | 171 | } |
|---|
| 169 | 172 | |
|---|
| 170 | 173 | /* Register dump */ |
|---|
| .. | .. |
|---|
| 474 | 477 | } |
|---|
| 475 | 478 | |
|---|
| 476 | 479 | /** |
|---|
| 480 | + * efx_nic_copy_stats - Copy stats from the DMA buffer in to an |
|---|
| 481 | + * intermediate buffer. This is used to get a consistent |
|---|
| 482 | + * set of stats while the DMA buffer can be written at any time |
|---|
| 483 | + * by the NIC. |
|---|
| 484 | + * @efx: The associated NIC. |
|---|
| 485 | + * @dest: Destination buffer. Must be the same size as the DMA buffer. |
|---|
| 486 | + */ |
|---|
| 487 | +int efx_nic_copy_stats(struct efx_nic *efx, __le64 *dest) |
|---|
| 488 | +{ |
|---|
| 489 | + __le64 *dma_stats = efx->stats_buffer.addr; |
|---|
| 490 | + __le64 generation_start, generation_end; |
|---|
| 491 | + int rc = 0, retry; |
|---|
| 492 | + |
|---|
| 493 | + if (!dest) |
|---|
| 494 | + return 0; |
|---|
| 495 | + |
|---|
| 496 | + if (!dma_stats) |
|---|
| 497 | + goto return_zeroes; |
|---|
| 498 | + |
|---|
| 499 | + /* If we're unlucky enough to read statistics during the DMA, wait |
|---|
| 500 | + * up to 10ms for it to finish (typically takes <500us) |
|---|
| 501 | + */ |
|---|
| 502 | + for (retry = 0; retry < 100; ++retry) { |
|---|
| 503 | + generation_end = dma_stats[efx->num_mac_stats - 1]; |
|---|
| 504 | + if (generation_end == EFX_MC_STATS_GENERATION_INVALID) |
|---|
| 505 | + goto return_zeroes; |
|---|
| 506 | + rmb(); |
|---|
| 507 | + memcpy(dest, dma_stats, efx->num_mac_stats * sizeof(__le64)); |
|---|
| 508 | + rmb(); |
|---|
| 509 | + generation_start = dma_stats[MC_CMD_MAC_GENERATION_START]; |
|---|
| 510 | + if (generation_end == generation_start) |
|---|
| 511 | + return 0; /* return good data */ |
|---|
| 512 | + udelay(100); |
|---|
| 513 | + } |
|---|
| 514 | + |
|---|
| 515 | + rc = -EIO; |
|---|
| 516 | + |
|---|
| 517 | +return_zeroes: |
|---|
| 518 | + memset(dest, 0, efx->num_mac_stats * sizeof(u64)); |
|---|
| 519 | + return rc; |
|---|
| 520 | +} |
|---|
| 521 | + |
|---|
| 522 | +/** |
|---|
| 477 | 523 | * efx_nic_update_stats - Convert statistics DMA buffer to array of u64 |
|---|
| 478 | 524 | * @desc: Array of &struct efx_hw_stat_desc describing the DMA buffer |
|---|
| 479 | 525 | * layout. DMA widths of 0, 16, 32 and 64 are supported; where |
|---|