提交 59bcaed5 编写于 作者: D David S. Miller

Merge branch 'for-davem' of git://git.kernel.org/pub/scm/linux/kernel/git/bwh/sfc-next

Ben Hutchings says:

====================
An assortment of changes for Linux 3.14:

1. Merge the sfc fixes that you have already merged into net.git.
   (The branch point for those was such that this does not bring in any
   other changes.)
2. Reduce log level for a generally useless warning message, from
   Robert Stonehouse.
3. Include BISTs in ethtool offline self-test for EF10 and recover from
   BISTs initiated through other functions, from Jon Cooper.
4. Improve a sanity check on RX completions.
5. Avoid incrementing RX dropped count while the interface is down, from
   Jon Cooper.
6. Improve hardware sensor naming and log messages, from Edward Cree.
7. Log all unexpected errors returned by firmware, from Edward Cree.
8. Expose another NVRAM partition to userland.
9. Some refactoring of the PTP code in preparation for EF10 support.
10. Various minor cleanups.
====================
Signed-off-by: NDavid S. Miller <davem@davemloft.net>
......@@ -14,6 +14,7 @@
#include "mcdi_pcol.h"
#include "nic.h"
#include "workarounds.h"
#include "selftest.h"
#include <linux/in.h>
#include <linux/jhash.h>
#include <linux/wait.h>
......@@ -277,11 +278,17 @@ static int efx_ef10_probe(struct efx_nic *efx)
static int efx_ef10_free_vis(struct efx_nic *efx)
{
int rc = efx_mcdi_rpc(efx, MC_CMD_FREE_VIS, NULL, 0, NULL, 0, NULL);
MCDI_DECLARE_BUF_OUT_OR_ERR(outbuf, 0);
size_t outlen;
int rc = efx_mcdi_rpc_quiet(efx, MC_CMD_FREE_VIS, NULL, 0,
outbuf, sizeof(outbuf), &outlen);
/* -EALREADY means nothing to free, so ignore */
if (rc == -EALREADY)
rc = 0;
if (rc)
efx_mcdi_display_error(efx, MC_CMD_FREE_VIS, 0, outbuf, outlen,
rc);
return rc;
}
......@@ -901,6 +908,7 @@ static int efx_ef10_try_update_nic_stats(struct efx_nic *efx)
return -EAGAIN;
/* Update derived statistics */
efx_nic_fix_nodesc_drop_stat(efx, &stats[EF10_STAT_rx_nodesc_drops]);
stats[EF10_STAT_rx_good_bytes] =
stats[EF10_STAT_rx_bytes] -
stats[EF10_STAT_rx_bytes_minus_good_bytes];
......@@ -1242,7 +1250,6 @@ static void efx_ef10_tx_init(struct efx_tx_queue *tx_queue)
fail:
WARN_ON(true);
netif_err(efx, hw, efx->net_dev, "%s: failed rc=%d\n", __func__, rc);
}
static void efx_ef10_tx_fini(struct efx_tx_queue *tx_queue)
......@@ -1256,7 +1263,7 @@ static void efx_ef10_tx_fini(struct efx_tx_queue *tx_queue)
MCDI_SET_DWORD(inbuf, FINI_TXQ_IN_INSTANCE,
tx_queue->queue);
rc = efx_mcdi_rpc(efx, MC_CMD_FINI_TXQ, inbuf, sizeof(inbuf),
rc = efx_mcdi_rpc_quiet(efx, MC_CMD_FINI_TXQ, inbuf, sizeof(inbuf),
outbuf, sizeof(outbuf), &outlen);
if (rc && rc != -EALREADY)
......@@ -1265,7 +1272,8 @@ static void efx_ef10_tx_fini(struct efx_tx_queue *tx_queue)
return;
fail:
netif_err(efx, hw, efx->net_dev, "%s: failed rc=%d\n", __func__, rc);
efx_mcdi_display_error(efx, MC_CMD_FINI_TXQ, MC_CMD_FINI_TXQ_IN_LEN,
outbuf, outlen, rc);
}
static void efx_ef10_tx_remove(struct efx_tx_queue *tx_queue)
......@@ -1480,14 +1488,9 @@ static void efx_ef10_rx_init(struct efx_rx_queue *rx_queue)
rc = efx_mcdi_rpc(efx, MC_CMD_INIT_RXQ, inbuf, inlen,
outbuf, sizeof(outbuf), &outlen);
if (rc)
goto fail;
WARN_ON(rc);
return;
fail:
WARN_ON(true);
netif_err(efx, hw, efx->net_dev, "%s: failed rc=%d\n", __func__, rc);
}
static void efx_ef10_rx_fini(struct efx_rx_queue *rx_queue)
......@@ -1501,7 +1504,7 @@ static void efx_ef10_rx_fini(struct efx_rx_queue *rx_queue)
MCDI_SET_DWORD(inbuf, FINI_RXQ_IN_INSTANCE,
efx_rx_queue_index(rx_queue));
rc = efx_mcdi_rpc(efx, MC_CMD_FINI_RXQ, inbuf, sizeof(inbuf),
rc = efx_mcdi_rpc_quiet(efx, MC_CMD_FINI_RXQ, inbuf, sizeof(inbuf),
outbuf, sizeof(outbuf), &outlen);
if (rc && rc != -EALREADY)
......@@ -1510,7 +1513,8 @@ static void efx_ef10_rx_fini(struct efx_rx_queue *rx_queue)
return;
fail:
netif_err(efx, hw, efx->net_dev, "%s: failed rc=%d\n", __func__, rc);
efx_mcdi_display_error(efx, MC_CMD_FINI_RXQ, MC_CMD_FINI_RXQ_IN_LEN,
outbuf, outlen, rc);
}
static void efx_ef10_rx_remove(struct efx_rx_queue *rx_queue)
......@@ -1647,15 +1651,7 @@ static int efx_ef10_ev_init(struct efx_channel *channel)
rc = efx_mcdi_rpc(efx, MC_CMD_INIT_EVQ, inbuf, inlen,
outbuf, sizeof(outbuf), &outlen);
if (rc)
goto fail;
/* IRQ return is ignored */
return 0;
fail:
netif_err(efx, hw, efx->net_dev, "%s: failed rc=%d\n", __func__, rc);
return rc;
}
......@@ -1669,7 +1665,7 @@ static void efx_ef10_ev_fini(struct efx_channel *channel)
MCDI_SET_DWORD(inbuf, FINI_EVQ_IN_INSTANCE, channel->channel);
rc = efx_mcdi_rpc(efx, MC_CMD_FINI_EVQ, inbuf, sizeof(inbuf),
rc = efx_mcdi_rpc_quiet(efx, MC_CMD_FINI_EVQ, inbuf, sizeof(inbuf),
outbuf, sizeof(outbuf), &outlen);
if (rc && rc != -EALREADY)
......@@ -1678,7 +1674,8 @@ static void efx_ef10_ev_fini(struct efx_channel *channel)
return;
fail:
netif_err(efx, hw, efx->net_dev, "%s: failed rc=%d\n", __func__, rc);
efx_mcdi_display_error(efx, MC_CMD_FINI_EVQ, MC_CMD_FINI_EVQ_IN_LEN,
outbuf, outlen, rc);
}
static void efx_ef10_ev_remove(struct efx_channel *channel)
......@@ -1765,6 +1762,8 @@ static int efx_ef10_handle_rx_event(struct efx_channel *channel,
((1 << ESF_DZ_RX_DSC_PTR_LBITS_WIDTH) - 1));
if (n_descs != rx_queue->scatter_n + 1) {
struct efx_ef10_nic_data *nic_data = efx->nic_data;
/* detect rx abort */
if (unlikely(n_descs == rx_queue->scatter_n)) {
WARN_ON(rx_bytes != 0);
......@@ -1772,10 +1771,13 @@ static int efx_ef10_handle_rx_event(struct efx_channel *channel,
return 0;
}
if (unlikely(rx_queue->scatter_n != 0)) {
/* Scattered packet completions cannot be
* merged, so something has gone wrong.
*/
/* Check that RX completion merging is valid, i.e.
* the current firmware supports it and this is a
* non-scattered packet.
*/
if (!(nic_data->datapath_caps &
(1 << MC_CMD_GET_CAPABILITIES_OUT_RX_BATCHING_LBN)) ||
rx_queue->scatter_n != 0 || rx_cont) {
efx_ef10_handle_rx_bad_lbits(
rx_queue, next_ptr_lbits,
(rx_queue->removed_count +
......@@ -1901,7 +1903,7 @@ static void efx_ef10_handle_driver_generated_event(struct efx_channel *channel,
* events, so efx_process_channel() won't refill the
* queue. Refill it here
*/
efx_fast_push_rx_descriptors(&channel->rx_queue);
efx_fast_push_rx_descriptors(&channel->rx_queue, true);
break;
default:
netif_err(efx, hw, efx->net_dev,
......@@ -2257,6 +2259,8 @@ static int efx_ef10_filter_push(struct efx_nic *efx,
outbuf, sizeof(outbuf), NULL);
if (rc == 0)
*handle = MCDI_QWORD(outbuf, FILTER_OP_OUT_HANDLE);
if (rc == -ENOSPC)
rc = -EBUSY; /* to match efx_farch_filter_insert() */
return rc;
}
......@@ -3195,6 +3199,87 @@ static int efx_ef10_mac_reconfigure(struct efx_nic *efx)
return efx_mcdi_set_mac(efx);
}
static int efx_ef10_start_bist(struct efx_nic *efx, u32 bist_type)
{
MCDI_DECLARE_BUF(inbuf, MC_CMD_START_BIST_IN_LEN);
MCDI_SET_DWORD(inbuf, START_BIST_IN_TYPE, bist_type);
return efx_mcdi_rpc(efx, MC_CMD_START_BIST, inbuf, sizeof(inbuf),
NULL, 0, NULL);
}
/* MC BISTs follow a different poll mechanism to phy BISTs.
* The BIST is done in the poll handler on the MC, and the MCDI command
* will block until the BIST is done.
*/
static int efx_ef10_poll_bist(struct efx_nic *efx)
{
int rc;
MCDI_DECLARE_BUF(outbuf, MC_CMD_POLL_BIST_OUT_LEN);
size_t outlen;
u32 result;
rc = efx_mcdi_rpc(efx, MC_CMD_POLL_BIST, NULL, 0,
outbuf, sizeof(outbuf), &outlen);
if (rc != 0)
return rc;
if (outlen < MC_CMD_POLL_BIST_OUT_LEN)
return -EIO;
result = MCDI_DWORD(outbuf, POLL_BIST_OUT_RESULT);
switch (result) {
case MC_CMD_POLL_BIST_PASSED:
netif_dbg(efx, hw, efx->net_dev, "BIST passed.\n");
return 0;
case MC_CMD_POLL_BIST_TIMEOUT:
netif_err(efx, hw, efx->net_dev, "BIST timed out\n");
return -EIO;
case MC_CMD_POLL_BIST_FAILED:
netif_err(efx, hw, efx->net_dev, "BIST failed.\n");
return -EIO;
default:
netif_err(efx, hw, efx->net_dev,
"BIST returned unknown result %u", result);
return -EIO;
}
}
static int efx_ef10_run_bist(struct efx_nic *efx, u32 bist_type)
{
int rc;
netif_dbg(efx, drv, efx->net_dev, "starting BIST type %u\n", bist_type);
rc = efx_ef10_start_bist(efx, bist_type);
if (rc != 0)
return rc;
return efx_ef10_poll_bist(efx);
}
static int
efx_ef10_test_chip(struct efx_nic *efx, struct efx_self_tests *tests)
{
int rc, rc2;
efx_reset_down(efx, RESET_TYPE_WORLD);
rc = efx_mcdi_rpc(efx, MC_CMD_ENABLE_OFFLINE_BIST,
NULL, 0, NULL, 0, NULL);
if (rc != 0)
goto out;
tests->memory = efx_ef10_run_bist(efx, MC_CMD_MC_MEM_BIST) ? -1 : 1;
tests->registers = efx_ef10_run_bist(efx, MC_CMD_REG_BIST) ? -1 : 1;
rc = efx_mcdi_reset(efx, RESET_TYPE_WORLD);
out:
rc2 = efx_reset_up(efx, RESET_TYPE_WORLD, rc == 0);
return rc ? rc : rc2;
}
#ifdef CONFIG_SFC_MTD
struct efx_ef10_nvram_type_info {
......@@ -3213,6 +3298,7 @@ static const struct efx_ef10_nvram_type_info efx_ef10_nvram_types[] = {
{ NVRAM_PARTITION_TYPE_EXPROM_CONFIG_PORT1, 0, 1, "sfc_exp_rom_cfg" },
{ NVRAM_PARTITION_TYPE_EXPROM_CONFIG_PORT2, 0, 2, "sfc_exp_rom_cfg" },
{ NVRAM_PARTITION_TYPE_EXPROM_CONFIG_PORT3, 0, 3, "sfc_exp_rom_cfg" },
{ NVRAM_PARTITION_TYPE_LICENSE, 0, 0, "sfc_license" },
{ NVRAM_PARTITION_TYPE_PHY_MIN, 0xff, 0, "sfc_phy_fw" },
};
......@@ -3336,6 +3422,7 @@ const struct efx_nic_type efx_hunt_a0_nic_type = {
.describe_stats = efx_ef10_describe_stats,
.update_stats = efx_ef10_update_stats,
.start_stats = efx_mcdi_mac_start_stats,
.pull_stats = efx_mcdi_mac_pull_stats,
.stop_stats = efx_mcdi_mac_stop_stats,
.set_id_led = efx_mcdi_set_id_led,
.push_irq_moderation = efx_ef10_push_irq_moderation,
......@@ -3345,7 +3432,7 @@ const struct efx_nic_type efx_hunt_a0_nic_type = {
.get_wol = efx_ef10_get_wol,
.set_wol = efx_ef10_set_wol,
.resume_wol = efx_port_dummy_op_void,
/* TODO: test_chip */
.test_chip = efx_ef10_test_chip,
.test_nvram = efx_mcdi_nvram_test_all,
.mcdi_request = efx_ef10_mcdi_request,
.mcdi_poll_response = efx_ef10_mcdi_poll_response,
......
......@@ -83,6 +83,7 @@ const char *const efx_reset_type_names[] = {
[RESET_TYPE_DMA_ERROR] = "DMA_ERROR",
[RESET_TYPE_TX_SKIP] = "TX_SKIP",
[RESET_TYPE_MC_FAILURE] = "MC_FAILURE",
[RESET_TYPE_MC_BIST] = "MC_BIST",
};
/* Reset workqueue. If any NIC has a hardware failure then a reset will be
......@@ -91,6 +92,12 @@ const char *const efx_reset_type_names[] = {
*/
static struct workqueue_struct *reset_workqueue;
/* How often and how many times to poll for a reset while waiting for a
* BIST that another function started to complete.
*/
#define BIST_WAIT_DELAY_MS 100
#define BIST_WAIT_DELAY_COUNT 100
/**************************************************************************
*
* Configurable values
......@@ -246,7 +253,7 @@ static int efx_process_channel(struct efx_channel *channel, int budget)
efx_channel_get_rx_queue(channel);
efx_rx_flush_packet(channel);
efx_fast_push_rx_descriptors(rx_queue);
efx_fast_push_rx_descriptors(rx_queue, true);
}
return spent;
......@@ -585,7 +592,7 @@ static void efx_start_datapath(struct efx_nic *efx)
EFX_MAX_FRAME_LEN(efx->net_dev->mtu) +
efx->type->rx_buffer_padding);
rx_buf_len = (sizeof(struct efx_rx_page_state) +
NET_IP_ALIGN + efx->rx_dma_len);
efx->rx_ip_align + efx->rx_dma_len);
if (rx_buf_len <= PAGE_SIZE) {
efx->rx_scatter = efx->type->always_rx_scatter;
efx->rx_buffer_order = 0;
......@@ -639,12 +646,16 @@ static void efx_start_datapath(struct efx_nic *efx)
efx_for_each_channel_rx_queue(rx_queue, channel) {
efx_init_rx_queue(rx_queue);
atomic_inc(&efx->active_queues);
efx_nic_generate_fill_event(rx_queue);
efx_stop_eventq(channel);
efx_fast_push_rx_descriptors(rx_queue, false);
efx_start_eventq(channel);
}
WARN_ON(channel->rx_pkt_n_frags);
}
efx_ptp_start_datapath(efx);
if (netif_device_present(efx->net_dev))
netif_tx_wake_all_queues(efx->net_dev);
}
......@@ -659,6 +670,8 @@ static void efx_stop_datapath(struct efx_nic *efx)
EFX_ASSERT_RESET_SERIALISED(efx);
BUG_ON(efx->port_enabled);
efx_ptp_stop_datapath(efx);
/* Stop RX refill */
efx_for_each_channel(channel, efx) {
efx_for_each_channel_rx_queue(rx_queue, channel)
......@@ -1047,18 +1060,23 @@ static void efx_start_port(struct efx_nic *efx)
mutex_lock(&efx->mac_lock);
efx->port_enabled = true;
/* efx_mac_work() might have been scheduled after efx_stop_port(),
* and then cancelled by efx_flush_all() */
/* Ensure MAC ingress/egress is enabled */
efx->type->reconfigure_mac(efx);
mutex_unlock(&efx->mac_lock);
}
/* Prevent efx_mac_work() and efx_monitor() from working */
/* Cancel work for MAC reconfiguration, periodic hardware monitoring
* and the async self-test, wait for them to finish and prevent them
* being scheduled again. This doesn't cover online resets, which
* should only be cancelled when removing the device.
*/
static void efx_stop_port(struct efx_nic *efx)
{
netif_dbg(efx, ifdown, efx->net_dev, "stop port\n");
EFX_ASSERT_RESET_SERIALISED(efx);
mutex_lock(&efx->mac_lock);
efx->port_enabled = false;
mutex_unlock(&efx->mac_lock);
......@@ -1066,6 +1084,10 @@ static void efx_stop_port(struct efx_nic *efx)
/* Serialise against efx_set_multicast_list() */
netif_addr_lock_bh(efx->net_dev);
netif_addr_unlock_bh(efx->net_dev);
cancel_delayed_work_sync(&efx->monitor_work);
efx_selftest_async_cancel(efx);
cancel_work_sync(&efx->mac_work);
}
static void efx_fini_port(struct efx_nic *efx)
......@@ -1671,18 +1693,10 @@ static void efx_start_all(struct efx_nic *efx)
}
efx->type->start_stats(efx);
}
/* Flush all delayed work. Should only be called when no more delayed work
* will be scheduled. This doesn't flush pending online resets (efx_reset),
* since we're holding the rtnl_lock at this point. */
static void efx_flush_all(struct efx_nic *efx)
{
/* Make sure the hardware monitor and event self-test are stopped */
cancel_delayed_work_sync(&efx->monitor_work);
efx_selftest_async_cancel(efx);
/* Stop scheduled port reconfigurations */
cancel_work_sync(&efx->mac_work);
efx->type->pull_stats(efx);
spin_lock_bh(&efx->stats_lock);
efx->type->update_stats(efx, NULL, NULL);
spin_unlock_bh(&efx->stats_lock);
}
/* Quiesce the hardware and software data path, and regular activity
......@@ -1698,12 +1712,16 @@ static void efx_stop_all(struct efx_nic *efx)
if (!efx->port_enabled)
return;
/* update stats before we go down so we can accurately count
* rx_nodesc_drops
*/
efx->type->pull_stats(efx);
spin_lock_bh(&efx->stats_lock);
efx->type->update_stats(efx, NULL, NULL);
spin_unlock_bh(&efx->stats_lock);
efx->type->stop_stats(efx);
efx_stop_port(efx);
/* Flush efx_mac_work(), refill_workqueue, monitor_work */
efx_flush_all(efx);
/* Stop the kernel transmit interface. This is only valid if
* the device is stopped or detached; otherwise the watchdog
* may fire immediately.
......@@ -2385,6 +2403,24 @@ int efx_try_recovery(struct efx_nic *efx)
return 0;
}
static void efx_wait_for_bist_end(struct efx_nic *efx)
{
int i;
for (i = 0; i < BIST_WAIT_DELAY_COUNT; ++i) {
if (efx_mcdi_poll_reboot(efx))
goto out;
msleep(BIST_WAIT_DELAY_MS);
}
netif_err(efx, drv, efx->net_dev, "Warning: No MC reboot after BIST mode\n");
out:
/* Either way unset the BIST flag. If we found no reboot we probably
* won't recover, but we should try.
*/
efx->mc_bist_for_other_fn = false;
}
/* The worker thread exists so that code that cannot sleep can
* schedule a reset for later.
*/
......@@ -2397,6 +2433,9 @@ static void efx_reset_work(struct work_struct *data)
pending = ACCESS_ONCE(efx->reset_pending);
method = fls(pending) - 1;
if (method == RESET_TYPE_MC_BIST)
efx_wait_for_bist_end(efx);
if ((method == RESET_TYPE_RECOVER_OR_DISABLE ||
method == RESET_TYPE_RECOVER_OR_ALL) &&
efx_try_recovery(efx))
......@@ -2435,6 +2474,7 @@ void efx_schedule_reset(struct efx_nic *efx, enum reset_type type)
case RESET_TYPE_WORLD:
case RESET_TYPE_DISABLE:
case RESET_TYPE_RECOVER_OR_DISABLE:
case RESET_TYPE_MC_BIST:
method = type;
netif_dbg(efx, drv, efx->net_dev, "scheduling %s reset\n",
RESET_TYPE(method));
......@@ -2542,6 +2582,8 @@ static int efx_init_struct(struct efx_nic *efx,
efx->net_dev = net_dev;
efx->rx_prefix_size = efx->type->rx_prefix_size;
efx->rx_ip_align =
NET_IP_ALIGN ? (efx->rx_prefix_size + NET_IP_ALIGN) % 4 : 0;
efx->rx_packet_hash_offset =
efx->type->rx_hash_offset - efx->type->rx_prefix_size;
spin_lock_init(&efx->stats_lock);
......
......@@ -37,7 +37,7 @@ int efx_probe_rx_queue(struct efx_rx_queue *rx_queue);
void efx_remove_rx_queue(struct efx_rx_queue *rx_queue);
void efx_init_rx_queue(struct efx_rx_queue *rx_queue);
void efx_fini_rx_queue(struct efx_rx_queue *rx_queue);
void efx_fast_push_rx_descriptors(struct efx_rx_queue *rx_queue);
void efx_fast_push_rx_descriptors(struct efx_rx_queue *rx_queue, bool atomic);
void efx_rx_slow_fill(unsigned long context);
void __efx_rx_packet(struct efx_channel *channel);
void efx_rx_packet(struct efx_rx_queue *rx_queue, unsigned int index,
......
......@@ -165,6 +165,7 @@ enum reset_type {
RESET_TYPE_DMA_ERROR,
RESET_TYPE_TX_SKIP,
RESET_TYPE_MC_FAILURE,
RESET_TYPE_MC_BIST,
RESET_TYPE_MAX,
};
......
......@@ -318,6 +318,8 @@ static int efx_ethtool_fill_self_tests(struct efx_nic *efx,
"eventq.int", NULL);
}
efx_fill_test(n++, strings, data, &tests->memory,
"core", 0, "memory", NULL);
efx_fill_test(n++, strings, data, &tests->registers,
"core", 0, "registers", NULL);
......
......@@ -2593,6 +2593,14 @@ void falcon_start_nic_stats(struct efx_nic *efx)
spin_unlock_bh(&efx->stats_lock);
}
/* We don't acutally pull stats on falcon. Wait 10ms so that
* they arrive when we call this just after start_stats
*/
void falcon_pull_nic_stats(struct efx_nic *efx)
{
msleep(10);
}
void falcon_stop_nic_stats(struct efx_nic *efx)
{
struct falcon_nic_data *nic_data = efx->nic_data;
......@@ -2672,6 +2680,7 @@ const struct efx_nic_type falcon_a1_nic_type = {
.describe_stats = falcon_describe_nic_stats,
.update_stats = falcon_update_nic_stats,
.start_stats = falcon_start_nic_stats,
.pull_stats = falcon_pull_nic_stats,
.stop_stats = falcon_stop_nic_stats,
.set_id_led = falcon_set_id_led,
.push_irq_moderation = falcon_push_irq_moderation,
......@@ -2765,6 +2774,7 @@ const struct efx_nic_type falcon_b0_nic_type = {
.describe_stats = falcon_describe_nic_stats,
.update_stats = falcon_update_nic_stats,
.start_stats = falcon_start_nic_stats,
.pull_stats = falcon_pull_nic_stats,
.stop_stats = falcon_stop_nic_stats,
.set_id_led = falcon_set_id_led,
.push_irq_moderation = falcon_push_irq_moderation,
......
......@@ -1147,7 +1147,7 @@ static void efx_farch_handle_generated_event(struct efx_channel *channel,
/* The queue must be empty, so we won't receive any rx
* events, so efx_process_channel() won't refill the
* queue. Refill it here */
efx_fast_push_rx_descriptors(rx_queue);
efx_fast_push_rx_descriptors(rx_queue, true);
} else if (rx_queue && magic == EFX_CHANNEL_MAGIC_RX_DRAIN(rx_queue)) {
efx_farch_handle_drain_event(channel);
} else if (code == _EFX_CHANNEL_MAGIC_TX_DRAIN) {
......
......@@ -42,6 +42,7 @@ struct efx_mcdi_async_param {
unsigned int cmd;
size_t inlen;
size_t outlen;
bool quiet;
efx_mcdi_async_completer *complete;
unsigned long cookie;
/* followed by request/response buffer */
......@@ -50,6 +51,7 @@ struct efx_mcdi_async_param {
static void efx_mcdi_timeout_async(unsigned long context);
static int efx_mcdi_drv_attach(struct efx_nic *efx, bool driver_operating,
bool *was_attached_out);
static bool efx_mcdi_poll_once(struct efx_nic *efx);
static inline struct efx_mcdi_iface *efx_mcdi(struct efx_nic *efx)
{
......@@ -190,6 +192,8 @@ static int efx_mcdi_errno(unsigned int mcdi_err)
TRANSLATE_ERROR(EALREADY);
TRANSLATE_ERROR(ENOSPC);
#undef TRANSLATE_ERROR
case MC_CMD_ERR_ENOTSUP:
return -EOPNOTSUPP;
case MC_CMD_ERR_ALLOC_FAIL:
return -ENOBUFS;
case MC_CMD_ERR_MAC_EXIST:
......@@ -237,6 +241,21 @@ static void efx_mcdi_read_response_header(struct efx_nic *efx)
}
}
static bool efx_mcdi_poll_once(struct efx_nic *efx)
{
struct efx_mcdi_iface *mcdi = efx_mcdi(efx);
rmb();
if (!efx->type->mcdi_poll_response(efx))
return false;
spin_lock_bh(&mcdi->iface_lock);
efx_mcdi_read_response_header(efx);
spin_unlock_bh(&mcdi->iface_lock);
return true;
}
static int efx_mcdi_poll(struct efx_nic *efx)
{
struct efx_mcdi_iface *mcdi = efx_mcdi(efx);
......@@ -272,18 +291,13 @@ static int efx_mcdi_poll(struct efx_nic *efx)
time = jiffies;
rmb();
if (efx->type->mcdi_poll_response(efx))
if (efx_mcdi_poll_once(efx))
break;
if (time_after(time, finish))
return -ETIMEDOUT;
}
spin_lock_bh(&mcdi->iface_lock);
efx_mcdi_read_response_header(efx);
spin_unlock_bh(&mcdi->iface_lock);
/* Return rc=0 like wait_event_timeout() */
return 0;
}
......@@ -391,8 +405,9 @@ static bool efx_mcdi_complete_async(struct efx_mcdi_iface *mcdi, bool timeout)
{
struct efx_nic *efx = mcdi->efx;
struct efx_mcdi_async_param *async;
size_t hdr_len, data_len;
size_t hdr_len, data_len, err_len;
efx_dword_t *outbuf;
MCDI_DECLARE_BUF_OUT_OR_ERR(errbuf, 0);
int rc;
if (cmpxchg(&mcdi->state,
......@@ -433,6 +448,13 @@ static bool efx_mcdi_complete_async(struct efx_mcdi_iface *mcdi, bool timeout)
outbuf = (efx_dword_t *)(async + 1);
efx->type->mcdi_read_response(efx, outbuf, hdr_len,
min(async->outlen, data_len));
if (!timeout && rc && !async->quiet) {
err_len = min(sizeof(errbuf), data_len);
efx->type->mcdi_read_response(efx, errbuf, hdr_len,
sizeof(errbuf));
efx_mcdi_display_error(efx, async->cmd, async->inlen, errbuf,
err_len, rc);
}
async->complete(efx, async->cookie, rc, outbuf, data_len);
kfree(async);
......@@ -508,18 +530,129 @@ efx_mcdi_check_supported(struct efx_nic *efx, unsigned int cmd, size_t inlen)
return 0;
}
static int _efx_mcdi_rpc_finish(struct efx_nic *efx, unsigned cmd, size_t inlen,
efx_dword_t *outbuf, size_t outlen,
size_t *outlen_actual, bool quiet)
{
struct efx_mcdi_iface *mcdi = efx_mcdi(efx);
MCDI_DECLARE_BUF_OUT_OR_ERR(errbuf, 0);
int rc;
if (mcdi->mode == MCDI_MODE_POLL)
rc = efx_mcdi_poll(efx);
else
rc = efx_mcdi_await_completion(efx);
if (rc != 0) {
netif_err(efx, hw, efx->net_dev,
"MC command 0x%x inlen %d mode %d timed out\n",
cmd, (int)inlen, mcdi->mode);
if (mcdi->mode == MCDI_MODE_EVENTS && efx_mcdi_poll_once(efx)) {
netif_err(efx, hw, efx->net_dev,
"MCDI request was completed without an event\n");
rc = 0;
}
/* Close the race with efx_mcdi_ev_cpl() executing just too late
* and completing a request we've just cancelled, by ensuring
* that the seqno check therein fails.
*/
spin_lock_bh(&mcdi->iface_lock);
++mcdi->seqno;
++mcdi->credits;
spin_unlock_bh(&mcdi->iface_lock);
}
if (rc != 0) {
if (outlen_actual)
*outlen_actual = 0;
} else {
size_t hdr_len, data_len, err_len;
/* At the very least we need a memory barrier here to ensure
* we pick up changes from efx_mcdi_ev_cpl(). Protect against
* a spurious efx_mcdi_ev_cpl() running concurrently by
* acquiring the iface_lock. */
spin_lock_bh(&mcdi->iface_lock);
rc = mcdi->resprc;
hdr_len = mcdi->resp_hdr_len;
data_len = mcdi->resp_data_len;
err_len = min(sizeof(errbuf), data_len);
spin_unlock_bh(&mcdi->iface_lock);
BUG_ON(rc > 0);
efx->type->mcdi_read_response(efx, outbuf, hdr_len,
min(outlen, data_len));
if (outlen_actual)
*outlen_actual = data_len;
efx->type->mcdi_read_response(efx, errbuf, hdr_len, err_len);
if (cmd == MC_CMD_REBOOT && rc == -EIO) {
/* Don't reset if MC_CMD_REBOOT returns EIO */
} else if (rc == -EIO || rc == -EINTR) {
netif_err(efx, hw, efx->net_dev, "MC fatal error %d\n",
-rc);
efx_schedule_reset(efx, RESET_TYPE_MC_FAILURE);
} else if (rc && !quiet) {
efx_mcdi_display_error(efx, cmd, inlen, errbuf, err_len,
rc);
}
if (rc == -EIO || rc == -EINTR) {
msleep(MCDI_STATUS_SLEEP_MS);
efx_mcdi_poll_reboot(efx);
mcdi->new_epoch = true;
}
}
efx_mcdi_release(mcdi);
return rc;
}
static int _efx_mcdi_rpc(struct efx_nic *efx, unsigned cmd,
const efx_dword_t *inbuf, size_t inlen,
efx_dword_t *outbuf, size_t outlen,
size_t *outlen_actual, bool quiet)
{
int rc;
rc = efx_mcdi_rpc_start(efx, cmd, inbuf, inlen);
if (rc) {
if (outlen_actual)
*outlen_actual = 0;
return rc;
}
return _efx_mcdi_rpc_finish(efx, cmd, inlen, outbuf, outlen,
outlen_actual, quiet);
}
int efx_mcdi_rpc(struct efx_nic *efx, unsigned cmd,
const efx_dword_t *inbuf, size_t inlen,
efx_dword_t *outbuf, size_t outlen,
size_t *outlen_actual)
{
int rc;
return _efx_mcdi_rpc(efx, cmd, inbuf, inlen, outbuf, outlen,
outlen_actual, false);
}
rc = efx_mcdi_rpc_start(efx, cmd, inbuf, inlen);
if (rc)
return rc;
return efx_mcdi_rpc_finish(efx, cmd, inlen,
outbuf, outlen, outlen_actual);
/* Normally, on receiving an error code in the MCDI response,
* efx_mcdi_rpc will log an error message containing (among other
* things) the raw error code, by means of efx_mcdi_display_error.
* This _quiet version suppresses that; if the caller wishes to log
* the error conditionally on the return code, it should call this
* function and is then responsible for calling efx_mcdi_display_error
* as needed.
*/
int efx_mcdi_rpc_quiet(struct efx_nic *efx, unsigned cmd,
const efx_dword_t *inbuf, size_t inlen,
efx_dword_t *outbuf, size_t outlen,
size_t *outlen_actual)
{
return _efx_mcdi_rpc(efx, cmd, inbuf, inlen, outbuf, outlen,
outlen_actual, true);
}
int efx_mcdi_rpc_start(struct efx_nic *efx, unsigned cmd,
......@@ -532,35 +665,19 @@ int efx_mcdi_rpc_start(struct efx_nic *efx, unsigned cmd,
if (rc)
return rc;
if (efx->mc_bist_for_other_fn)
return -ENETDOWN;
efx_mcdi_acquire_sync(mcdi);
efx_mcdi_send_request(efx, cmd, inbuf, inlen);
return 0;
}
/**
* efx_mcdi_rpc_async - Schedule an MCDI command to run asynchronously
* @efx: NIC through which to issue the command
* @cmd: Command type number
* @inbuf: Command parameters
* @inlen: Length of command parameters, in bytes
* @outlen: Length to allocate for response buffer, in bytes
* @complete: Function to be called on completion or cancellation.
* @cookie: Arbitrary value to be passed to @complete.
*
* This function does not sleep and therefore may be called in atomic
* context. It will fail if event queues are disabled or if MCDI
* event completions have been disabled due to an error.
*
* If it succeeds, the @complete function will be called exactly once
* in atomic context, when one of the following occurs:
* (a) the completion event is received (in NAPI context)
* (b) event queues are disabled (in the process that disables them)
* (c) the request times-out (in timer context)
*/
int
efx_mcdi_rpc_async(struct efx_nic *efx, unsigned int cmd,
const efx_dword_t *inbuf, size_t inlen, size_t outlen,
efx_mcdi_async_completer *complete, unsigned long cookie)
static int _efx_mcdi_rpc_async(struct efx_nic *efx, unsigned int cmd,
const efx_dword_t *inbuf, size_t inlen,
size_t outlen,
efx_mcdi_async_completer *complete,
unsigned long cookie, bool quiet)
{
struct efx_mcdi_iface *mcdi = efx_mcdi(efx);
struct efx_mcdi_async_param *async;
......@@ -570,6 +687,9 @@ efx_mcdi_rpc_async(struct efx_nic *efx, unsigned int cmd,
if (rc)
return rc;
if (efx->mc_bist_for_other_fn)
return -ENETDOWN;
async = kmalloc(sizeof(*async) + ALIGN(max(inlen, outlen), 4),
GFP_ATOMIC);
if (!async)
......@@ -578,6 +698,7 @@ efx_mcdi_rpc_async(struct efx_nic *efx, unsigned int cmd,
async->cmd = cmd;
async->inlen = inlen;
async->outlen = outlen;
async->quiet = quiet;
async->complete = complete;
async->cookie = cookie;
memcpy(async + 1, inbuf, inlen);
......@@ -606,71 +727,73 @@ efx_mcdi_rpc_async(struct efx_nic *efx, unsigned int cmd,
return rc;
}
/**
* efx_mcdi_rpc_async - Schedule an MCDI command to run asynchronously
* @efx: NIC through which to issue the command
* @cmd: Command type number
* @inbuf: Command parameters
* @inlen: Length of command parameters, in bytes
* @outlen: Length to allocate for response buffer, in bytes
* @complete: Function to be called on completion or cancellation.
* @cookie: Arbitrary value to be passed to @complete.
*
* This function does not sleep and therefore may be called in atomic
* context. It will fail if event queues are disabled or if MCDI
* event completions have been disabled due to an error.
*
* If it succeeds, the @complete function will be called exactly once
* in atomic context, when one of the following occurs:
* (a) the completion event is received (in NAPI context)
* (b) event queues are disabled (in the process that disables them)
* (c) the request times-out (in timer context)
*/
int
efx_mcdi_rpc_async(struct efx_nic *efx, unsigned int cmd,
const efx_dword_t *inbuf, size_t inlen, size_t outlen,
efx_mcdi_async_completer *complete, unsigned long cookie)
{
return _efx_mcdi_rpc_async(efx, cmd, inbuf, inlen, outlen, complete,
cookie, false);
}
int efx_mcdi_rpc_async_quiet(struct efx_nic *efx, unsigned int cmd,
const efx_dword_t *inbuf, size_t inlen,
size_t outlen, efx_mcdi_async_completer *complete,
unsigned long cookie)
{
return _efx_mcdi_rpc_async(efx, cmd, inbuf, inlen, outlen, complete,
cookie, true);
}
int efx_mcdi_rpc_finish(struct efx_nic *efx, unsigned cmd, size_t inlen,
efx_dword_t *outbuf, size_t outlen,
size_t *outlen_actual)
{
struct efx_mcdi_iface *mcdi = efx_mcdi(efx);
int rc;
if (mcdi->mode == MCDI_MODE_POLL)
rc = efx_mcdi_poll(efx);
else
rc = efx_mcdi_await_completion(efx);
if (rc != 0) {
/* Close the race with efx_mcdi_ev_cpl() executing just too late
* and completing a request we've just cancelled, by ensuring
* that the seqno check therein fails.
*/
spin_lock_bh(&mcdi->iface_lock);
++mcdi->seqno;
++mcdi->credits;
spin_unlock_bh(&mcdi->iface_lock);
netif_err(efx, hw, efx->net_dev,
"MC command 0x%x inlen %d mode %d timed out\n",
cmd, (int)inlen, mcdi->mode);
} else {
size_t hdr_len, data_len;
/* At the very least we need a memory barrier here to ensure
* we pick up changes from efx_mcdi_ev_cpl(). Protect against
* a spurious efx_mcdi_ev_cpl() running concurrently by
* acquiring the iface_lock. */
spin_lock_bh(&mcdi->iface_lock);
rc = mcdi->resprc;
hdr_len = mcdi->resp_hdr_len;
data_len = mcdi->resp_data_len;
spin_unlock_bh(&mcdi->iface_lock);
BUG_ON(rc > 0);
return _efx_mcdi_rpc_finish(efx, cmd, inlen, outbuf, outlen,
outlen_actual, false);
}
if (rc == 0) {
efx->type->mcdi_read_response(efx, outbuf, hdr_len,
min(outlen, data_len));
if (outlen_actual != NULL)
*outlen_actual = data_len;
} else if (cmd == MC_CMD_REBOOT && rc == -EIO)
; /* Don't reset if MC_CMD_REBOOT returns EIO */
else if (rc == -EIO || rc == -EINTR) {
netif_err(efx, hw, efx->net_dev, "MC fatal error %d\n",
-rc);
efx_schedule_reset(efx, RESET_TYPE_MC_FAILURE);
} else
netif_dbg(efx, hw, efx->net_dev,
"MC command 0x%x inlen %d failed rc=%d\n",
cmd, (int)inlen, -rc);
int efx_mcdi_rpc_finish_quiet(struct efx_nic *efx, unsigned cmd, size_t inlen,
efx_dword_t *outbuf, size_t outlen,
size_t *outlen_actual)
{
return _efx_mcdi_rpc_finish(efx, cmd, inlen, outbuf, outlen,
outlen_actual, true);
}
if (rc == -EIO || rc == -EINTR) {
msleep(MCDI_STATUS_SLEEP_MS);
efx_mcdi_poll_reboot(efx);
mcdi->new_epoch = true;
}
}
void efx_mcdi_display_error(struct efx_nic *efx, unsigned cmd,
size_t inlen, efx_dword_t *outbuf,
size_t outlen, int rc)
{
int code = 0, err_arg = 0;
efx_mcdi_release(mcdi);
return rc;
if (outlen >= MC_CMD_ERR_CODE_OFST + 4)
code = MCDI_DWORD(outbuf, ERR_CODE);
if (outlen >= MC_CMD_ERR_ARG_OFST + 4)
err_arg = MCDI_DWORD(outbuf, ERR_ARG);
netif_err(efx, hw, efx->net_dev,
"MC command 0x%x inlen %d failed rc=%d (raw=%d) arg=%d\n",
cmd, (int)inlen, rc, code, err_arg);
}
/* Switch to polled MCDI completions. This can be called in various
......@@ -815,6 +938,30 @@ static void efx_mcdi_ev_death(struct efx_nic *efx, int rc)
spin_unlock(&mcdi->iface_lock);
}
/* The MC is going down in to BIST mode. set the BIST flag to block
* new MCDI, cancel any outstanding MCDI and and schedule a BIST-type reset
* (which doesn't actually execute a reset, it waits for the controlling
* function to reset it).
*/
static void efx_mcdi_ev_bist(struct efx_nic *efx)
{
struct efx_mcdi_iface *mcdi = efx_mcdi(efx);
spin_lock(&mcdi->iface_lock);
efx->mc_bist_for_other_fn = true;
if (efx_mcdi_complete_sync(mcdi)) {
if (mcdi->mode == MCDI_MODE_EVENTS) {
mcdi->resprc = -EIO;
mcdi->resp_hdr_len = 0;
mcdi->resp_data_len = 0;
++mcdi->credits;
}
}
mcdi->new_epoch = true;
efx_schedule_reset(efx, RESET_TYPE_MC_BIST);
spin_unlock(&mcdi->iface_lock);
}
/* Called from falcon_process_eventq for MCDI events */
void efx_mcdi_process_event(struct efx_channel *channel,
efx_qword_t *event)
......@@ -848,14 +995,18 @@ void efx_mcdi_process_event(struct efx_channel *channel,
efx_mcdi_sensor_event(efx, event);
break;
case MCDI_EVENT_CODE_SCHEDERR:
netif_info(efx, hw, efx->net_dev,
"MC Scheduler error address=0x%x\n", data);
netif_dbg(efx, hw, efx->net_dev,
"MC Scheduler alert (0x%x)\n", data);
break;
case MCDI_EVENT_CODE_REBOOT:
case MCDI_EVENT_CODE_MC_REBOOT:
netif_info(efx, hw, efx->net_dev, "MC Reboot\n");
efx_mcdi_ev_death(efx, -EIO);
break;
case MCDI_EVENT_CODE_MC_BIST:
netif_info(efx, hw, efx->net_dev, "MC entered BIST mode\n");
efx_mcdi_ev_bist(efx);
break;
case MCDI_EVENT_CODE_MAC_STATS_DMA:
/* MAC stats are gather lazily. We can ignore this. */
break;
......@@ -1078,13 +1229,6 @@ int efx_mcdi_log_ctrl(struct efx_nic *efx, bool evq, bool uart, u32 dest_evq)
rc = efx_mcdi_rpc(efx, MC_CMD_LOG_CTRL, inbuf, sizeof(inbuf),
NULL, 0, NULL);
if (rc)
goto fail;
return 0;
fail:
netif_err(efx, hw, efx->net_dev, "%s: failed rc=%d\n", __func__, rc);
return rc;
}
......@@ -1201,7 +1345,7 @@ int efx_mcdi_nvram_test_all(struct efx_nic *efx)
static int efx_mcdi_read_assertion(struct efx_nic *efx)
{
MCDI_DECLARE_BUF(inbuf, MC_CMD_GET_ASSERTS_IN_LEN);
MCDI_DECLARE_BUF(outbuf, MC_CMD_GET_ASSERTS_OUT_LEN);
MCDI_DECLARE_BUF_OUT_OR_ERR(outbuf, MC_CMD_GET_ASSERTS_OUT_LEN);
unsigned int flags, index;
const char *reason;
size_t outlen;
......@@ -1216,13 +1360,17 @@ static int efx_mcdi_read_assertion(struct efx_nic *efx)
retry = 2;
do {
MCDI_SET_DWORD(inbuf, GET_ASSERTS_IN_CLEAR, 1);
rc = efx_mcdi_rpc(efx, MC_CMD_GET_ASSERTS,
inbuf, MC_CMD_GET_ASSERTS_IN_LEN,
outbuf, sizeof(outbuf), &outlen);
rc = efx_mcdi_rpc_quiet(efx, MC_CMD_GET_ASSERTS,
inbuf, MC_CMD_GET_ASSERTS_IN_LEN,
outbuf, sizeof(outbuf), &outlen);
} while ((rc == -EINTR || rc == -EIO) && retry-- > 0);
if (rc)
if (rc) {
efx_mcdi_display_error(efx, MC_CMD_GET_ASSERTS,
MC_CMD_GET_ASSERTS_IN_LEN, outbuf,
outlen, rc);
return rc;
}
if (outlen < MC_CMD_GET_ASSERTS_OUT_LEN)
return -EIO;
......@@ -1300,18 +1448,11 @@ void efx_mcdi_set_id_led(struct efx_nic *efx, enum efx_led_mode mode)
rc = efx_mcdi_rpc(efx, MC_CMD_SET_ID_LED, inbuf, sizeof(inbuf),
NULL, 0, NULL);
if (rc)
netif_err(efx, hw, efx->net_dev, "%s: failed rc=%d\n",
__func__, rc);
}
static int efx_mcdi_reset_port(struct efx_nic *efx)
{
int rc = efx_mcdi_rpc(efx, MC_CMD_ENTITY_RESET, NULL, 0, NULL, 0, NULL);
if (rc)
netif_err(efx, hw, efx->net_dev, "%s: failed rc=%d\n",
__func__, rc);
return rc;
return efx_mcdi_rpc(efx, MC_CMD_ENTITY_RESET, NULL, 0, NULL, 0, NULL);
}
static int efx_mcdi_reset_mc(struct efx_nic *efx)
......@@ -1328,7 +1469,6 @@ static int efx_mcdi_reset_mc(struct efx_nic *efx)
return 0;
if (rc == 0)
rc = -EIO;
netif_err(efx, hw, efx->net_dev, "%s: failed rc=%d\n", __func__, rc);
return rc;
}
......@@ -1430,13 +1570,6 @@ int efx_mcdi_wol_filter_remove(struct efx_nic *efx, int id)
rc = efx_mcdi_rpc(efx, MC_CMD_WOL_FILTER_REMOVE, inbuf, sizeof(inbuf),
NULL, 0, NULL);
if (rc)
goto fail;
return 0;
fail:
netif_err(efx, hw, efx->net_dev, "%s: failed rc=%d\n", __func__, rc);
return rc;
}
......@@ -1477,13 +1610,6 @@ int efx_mcdi_wol_filter_reset(struct efx_nic *efx)
int rc;
rc = efx_mcdi_rpc(efx, MC_CMD_WOL_FILTER_RESET, NULL, 0, NULL, 0, NULL);
if (rc)
goto fail;
return 0;
fail:
netif_err(efx, hw, efx->net_dev, "%s: failed rc=%d\n", __func__, rc);
return rc;
}
......@@ -1513,13 +1639,6 @@ static int efx_mcdi_nvram_update_start(struct efx_nic *efx, unsigned int type)
rc = efx_mcdi_rpc(efx, MC_CMD_NVRAM_UPDATE_START, inbuf, sizeof(inbuf),
NULL, 0, NULL);
if (rc)
goto fail;
return 0;
fail:
netif_err(efx, hw, efx->net_dev, "%s: failed rc=%d\n", __func__, rc);
return rc;
}
......@@ -1539,14 +1658,10 @@ static int efx_mcdi_nvram_read(struct efx_nic *efx, unsigned int type,
rc = efx_mcdi_rpc(efx, MC_CMD_NVRAM_READ, inbuf, sizeof(inbuf),
outbuf, sizeof(outbuf), &outlen);
if (rc)
goto fail;
return rc;
memcpy(buffer, MCDI_PTR(outbuf, NVRAM_READ_OUT_READ_BUFFER), length);
return 0;
fail:
netif_err(efx, hw, efx->net_dev, "%s: failed rc=%d\n", __func__, rc);
return rc;
}
static int efx_mcdi_nvram_write(struct efx_nic *efx, unsigned int type,
......@@ -1566,13 +1681,6 @@ static int efx_mcdi_nvram_write(struct efx_nic *efx, unsigned int type,
rc = efx_mcdi_rpc(efx, MC_CMD_NVRAM_WRITE, inbuf,
ALIGN(MC_CMD_NVRAM_WRITE_IN_LEN(length), 4),
NULL, 0, NULL);
if (rc)
goto fail;
return 0;
fail:
netif_err(efx, hw, efx->net_dev, "%s: failed rc=%d\n", __func__, rc);
return rc;
}
......@@ -1590,13 +1698,6 @@ static int efx_mcdi_nvram_erase(struct efx_nic *efx, unsigned int type,
rc = efx_mcdi_rpc(efx, MC_CMD_NVRAM_ERASE, inbuf, sizeof(inbuf),
NULL, 0, NULL);
if (rc)
goto fail;
return 0;
fail:
netif_err(efx, hw, efx->net_dev, "%s: failed rc=%d\n", __func__, rc);
return rc;
}
......@@ -1611,13 +1712,6 @@ static int efx_mcdi_nvram_update_finish(struct efx_nic *efx, unsigned int type)
rc = efx_mcdi_rpc(efx, MC_CMD_NVRAM_UPDATE_FINISH, inbuf, sizeof(inbuf),
NULL, 0, NULL);
if (rc)
goto fail;
return 0;
fail:
netif_err(efx, hw, efx->net_dev, "%s: failed rc=%d\n", __func__, rc);
return rc;
}
......
......@@ -116,12 +116,19 @@ void efx_mcdi_fini(struct efx_nic *efx);
int efx_mcdi_rpc(struct efx_nic *efx, unsigned cmd, const efx_dword_t *inbuf,
size_t inlen, efx_dword_t *outbuf, size_t outlen,
size_t *outlen_actual);
int efx_mcdi_rpc_quiet(struct efx_nic *efx, unsigned cmd,
const efx_dword_t *inbuf, size_t inlen,
efx_dword_t *outbuf, size_t outlen,
size_t *outlen_actual);
int efx_mcdi_rpc_start(struct efx_nic *efx, unsigned cmd,
const efx_dword_t *inbuf, size_t inlen);
int efx_mcdi_rpc_finish(struct efx_nic *efx, unsigned cmd, size_t inlen,
efx_dword_t *outbuf, size_t outlen,
size_t *outlen_actual);
int efx_mcdi_rpc_finish_quiet(struct efx_nic *efx, unsigned cmd,
size_t inlen, efx_dword_t *outbuf,
size_t outlen, size_t *outlen_actual);
typedef void efx_mcdi_async_completer(struct efx_nic *efx,
unsigned long cookie, int rc,
......@@ -131,6 +138,15 @@ int efx_mcdi_rpc_async(struct efx_nic *efx, unsigned int cmd,
const efx_dword_t *inbuf, size_t inlen, size_t outlen,
efx_mcdi_async_completer *complete,
unsigned long cookie);
int efx_mcdi_rpc_async_quiet(struct efx_nic *efx, unsigned int cmd,
const efx_dword_t *inbuf, size_t inlen,
size_t outlen,
efx_mcdi_async_completer *complete,
unsigned long cookie);
void efx_mcdi_display_error(struct efx_nic *efx, unsigned cmd,
size_t inlen, efx_dword_t *outbuf,
size_t outlen, int rc);
int efx_mcdi_poll_reboot(struct efx_nic *efx);
void efx_mcdi_mode_poll(struct efx_nic *efx);
......@@ -147,6 +163,8 @@ void efx_mcdi_sensor_event(struct efx_nic *efx, efx_qword_t *ev);
*/
#define MCDI_DECLARE_BUF(_name, _len) \
efx_dword_t _name[DIV_ROUND_UP(_len, 4)]
#define MCDI_DECLARE_BUF_OUT_OR_ERR(_name, _len) \
MCDI_DECLARE_BUF(_name, max_t(size_t, _len, 8))
#define _MCDI_PTR(_buf, _offset) \
((u8 *)(_buf) + (_offset))
#define MCDI_PTR(_buf, _field) \
......@@ -301,6 +319,7 @@ int efx_mcdi_set_mac(struct efx_nic *efx);
#define EFX_MC_STATS_GENERATION_INVALID ((__force __le64)(-1))
void efx_mcdi_mac_start_stats(struct efx_nic *efx);
void efx_mcdi_mac_stop_stats(struct efx_nic *efx);
void efx_mcdi_mac_pull_stats(struct efx_nic *efx);
bool efx_mcdi_mac_check_fault(struct efx_nic *efx);
enum reset_type efx_mcdi_map_reset_reason(enum reset_type reason);
int efx_mcdi_reset(struct efx_nic *efx, enum reset_type method);
......
......@@ -24,6 +24,15 @@ enum efx_hwmon_type {
EFX_HWMON_IN, /* voltage */
EFX_HWMON_CURR, /* current */
EFX_HWMON_POWER, /* power */
EFX_HWMON_TYPES_COUNT
};
static const char *const efx_hwmon_unit[EFX_HWMON_TYPES_COUNT] = {
[EFX_HWMON_TEMP] = " degC",
[EFX_HWMON_COOL] = " rpm", /* though nonsense for a heatsink */
[EFX_HWMON_IN] = " mV",
[EFX_HWMON_CURR] = " mA",
[EFX_HWMON_POWER] = " W",
};
static const struct {
......@@ -33,13 +42,13 @@ static const struct {
} efx_mcdi_sensor_type[] = {
#define SENSOR(name, label, hwmon_type, port) \
[MC_CMD_SENSOR_##name] = { label, EFX_HWMON_ ## hwmon_type, port }
SENSOR(CONTROLLER_TEMP, "Controller ext. temp.", TEMP, -1),
SENSOR(CONTROLLER_TEMP, "Controller board temp.", TEMP, -1),
SENSOR(PHY_COMMON_TEMP, "PHY temp.", TEMP, -1),
SENSOR(CONTROLLER_COOLING, "Controller cooling", COOL, -1),
SENSOR(CONTROLLER_COOLING, "Controller heat sink", COOL, -1),
SENSOR(PHY0_TEMP, "PHY temp.", TEMP, 0),
SENSOR(PHY0_COOLING, "PHY cooling", COOL, 0),
SENSOR(PHY0_COOLING, "PHY heat sink", COOL, 0),
SENSOR(PHY1_TEMP, "PHY temp.", TEMP, 1),
SENSOR(PHY1_COOLING, "PHY cooling", COOL, 1),
SENSOR(PHY1_COOLING, "PHY heat sink", COOL, 1),
SENSOR(IN_1V0, "1.0V supply", IN, -1),
SENSOR(IN_1V2, "1.2V supply", IN, -1),
SENSOR(IN_1V8, "1.8V supply", IN, -1),
......@@ -47,36 +56,42 @@ static const struct {
SENSOR(IN_3V3, "3.3V supply", IN, -1),
SENSOR(IN_12V0, "12.0V supply", IN, -1),
SENSOR(IN_1V2A, "1.2V analogue supply", IN, -1),
SENSOR(IN_VREF, "ref. voltage", IN, -1),
SENSOR(OUT_VAOE, "AOE power supply", IN, -1),
SENSOR(AOE_TEMP, "AOE temp.", TEMP, -1),
SENSOR(PSU_AOE_TEMP, "AOE PSU temp.", TEMP, -1),
SENSOR(PSU_TEMP, "Controller PSU temp.", TEMP, -1),
SENSOR(FAN_0, NULL, COOL, -1),
SENSOR(FAN_1, NULL, COOL, -1),
SENSOR(FAN_2, NULL, COOL, -1),
SENSOR(FAN_3, NULL, COOL, -1),
SENSOR(FAN_4, NULL, COOL, -1),
SENSOR(IN_VREF, "Ref. voltage", IN, -1),
SENSOR(OUT_VAOE, "AOE FPGA supply", IN, -1),
SENSOR(AOE_TEMP, "AOE FPGA temp.", TEMP, -1),
SENSOR(PSU_AOE_TEMP, "AOE regulator temp.", TEMP, -1),
SENSOR(PSU_TEMP, "Controller regulator temp.",
TEMP, -1),
SENSOR(FAN_0, "Fan 0", COOL, -1),
SENSOR(FAN_1, "Fan 1", COOL, -1),
SENSOR(FAN_2, "Fan 2", COOL, -1),
SENSOR(FAN_3, "Fan 3", COOL, -1),
SENSOR(FAN_4, "Fan 4", COOL, -1),
SENSOR(IN_VAOE, "AOE input supply", IN, -1),
SENSOR(OUT_IAOE, "AOE output current", CURR, -1),
SENSOR(IN_IAOE, "AOE input current", CURR, -1),
SENSOR(NIC_POWER, "Board power use", POWER, -1),
SENSOR(IN_0V9, "0.9V supply", IN, -1),
SENSOR(IN_I0V9, "0.9V input current", CURR, -1),
SENSOR(IN_I1V2, "1.2V input current", CURR, -1),
SENSOR(IN_0V9_ADC, "0.9V supply (at ADC)", IN, -1),
SENSOR(CONTROLLER_2_TEMP, "Controller ext. temp. 2", TEMP, -1),
SENSOR(VREG_INTERNAL_TEMP, "Voltage regulator temp.", TEMP, -1),
SENSOR(IN_I0V9, "0.9V supply current", CURR, -1),
SENSOR(IN_I1V2, "1.2V supply current", CURR, -1),
SENSOR(IN_0V9_ADC, "0.9V supply (ext. ADC)", IN, -1),
SENSOR(CONTROLLER_2_TEMP, "Controller board temp. 2", TEMP, -1),
SENSOR(VREG_INTERNAL_TEMP, "Regulator die temp.", TEMP, -1),
SENSOR(VREG_0V9_TEMP, "0.9V regulator temp.", TEMP, -1),
SENSOR(VREG_1V2_TEMP, "1.2V regulator temp.", TEMP, -1),
SENSOR(CONTROLLER_VPTAT, "Controller int. temp. raw", IN, -1),
SENSOR(CONTROLLER_INTERNAL_TEMP, "Controller int. temp.", TEMP, -1),
SENSOR(CONTROLLER_VPTAT,
"Controller PTAT voltage (int. ADC)", IN, -1),
SENSOR(CONTROLLER_INTERNAL_TEMP,
"Controller die temp. (int. ADC)", TEMP, -1),
SENSOR(CONTROLLER_VPTAT_EXTADC,
"Controller int. temp. raw (at ADC)", IN, -1),
"Controller PTAT voltage (ext. ADC)", IN, -1),
SENSOR(CONTROLLER_INTERNAL_TEMP_EXTADC,
"Controller int. temp. (via ADC)", TEMP, -1),
"Controller die temp. (ext. ADC)", TEMP, -1),
SENSOR(AMBIENT_TEMP, "Ambient temp.", TEMP, -1),
SENSOR(AIRFLOW, "Air flow raw", IN, -1),
SENSOR(VDD08D_VSS08D_CSR, "0.9V die (int. ADC)", IN, -1),
SENSOR(VDD08D_VSS08D_CSR_EXTADC, "0.9V die (ext. ADC)", IN, -1),
SENSOR(HOTPOINT_TEMP, "Controller board temp. (hotpoint)", TEMP, -1),
#undef SENSOR
};
......@@ -91,7 +106,8 @@ static const char *const sensor_status_names[] = {
void efx_mcdi_sensor_event(struct efx_nic *efx, efx_qword_t *ev)
{
unsigned int type, state, value;
const char *name = NULL, *state_txt;
enum efx_hwmon_type hwmon_type = EFX_HWMON_UNKNOWN;
const char *name = NULL, *state_txt, *unit;
type = EFX_QWORD_FIELD(*ev, MCDI_EVENT_SENSOREVT_MONITOR);
state = EFX_QWORD_FIELD(*ev, MCDI_EVENT_SENSOREVT_STATE);
......@@ -99,16 +115,22 @@ void efx_mcdi_sensor_event(struct efx_nic *efx, efx_qword_t *ev)
/* Deal gracefully with the board having more drivers than we
* know about, but do not expect new sensor states. */
if (type < ARRAY_SIZE(efx_mcdi_sensor_type))
if (type < ARRAY_SIZE(efx_mcdi_sensor_type)) {
name = efx_mcdi_sensor_type[type].label;
hwmon_type = efx_mcdi_sensor_type[type].hwmon_type;
}
if (!name)
name = "No sensor name available";
EFX_BUG_ON_PARANOID(state >= ARRAY_SIZE(sensor_status_names));
state_txt = sensor_status_names[state];
EFX_BUG_ON_PARANOID(hwmon_type >= EFX_HWMON_TYPES_COUNT);
unit = efx_hwmon_unit[hwmon_type];
if (!unit)
unit = "";
netif_err(efx, hw, efx->net_dev,
"Sensor %d (%s) reports condition '%s' for raw value %d\n",
type, name, state_txt, value);
"Sensor %d (%s) reports condition '%s' for value %d%s\n",
type, name, state_txt, value, unit);
}
#ifdef CONFIG_SFC_MCDI_MON
......
......@@ -90,13 +90,6 @@ static int efx_mcdi_set_link(struct efx_nic *efx, u32 capabilities,
rc = efx_mcdi_rpc(efx, MC_CMD_SET_LINK, inbuf, sizeof(inbuf),
NULL, 0, NULL);
if (rc)
goto fail;
return 0;
fail:
netif_err(efx, hw, efx->net_dev, "%s: failed rc=%d\n", __func__, rc);
return rc;
}
......@@ -143,17 +136,13 @@ static int efx_mcdi_mdio_read(struct net_device *net_dev,
rc = efx_mcdi_rpc(efx, MC_CMD_MDIO_READ, inbuf, sizeof(inbuf),
outbuf, sizeof(outbuf), &outlen);
if (rc)
goto fail;
return rc;
if (MCDI_DWORD(outbuf, MDIO_READ_OUT_STATUS) !=
MC_CMD_MDIO_STATUS_GOOD)
return -EIO;
return (u16)MCDI_DWORD(outbuf, MDIO_READ_OUT_VALUE);
fail:
netif_err(efx, hw, efx->net_dev, "%s: failed rc=%d\n", __func__, rc);
return rc;
}
static int efx_mcdi_mdio_write(struct net_device *net_dev,
......@@ -174,17 +163,13 @@ static int efx_mcdi_mdio_write(struct net_device *net_dev,
rc = efx_mcdi_rpc(efx, MC_CMD_MDIO_WRITE, inbuf, sizeof(inbuf),
outbuf, sizeof(outbuf), &outlen);
if (rc)
goto fail;
return rc;
if (MCDI_DWORD(outbuf, MDIO_WRITE_OUT_STATUS) !=
MC_CMD_MDIO_STATUS_GOOD)
return -EIO;
return 0;
fail:
netif_err(efx, hw, efx->net_dev, "%s: failed rc=%d\n", __func__, rc);
return rc;
}
static u32 mcdi_to_ethtool_cap(u32 media, u32 cap)
......@@ -487,17 +472,14 @@ static bool efx_mcdi_phy_poll(struct efx_nic *efx)
rc = efx_mcdi_rpc(efx, MC_CMD_GET_LINK, NULL, 0,
outbuf, sizeof(outbuf), NULL);
if (rc) {
netif_err(efx, hw, efx->net_dev, "%s: failed rc=%d\n",
__func__, rc);
if (rc)
efx->link_state.up = false;
} else {
else
efx_mcdi_phy_decode_link(
efx, &efx->link_state,
MCDI_DWORD(outbuf, GET_LINK_OUT_LINK_SPEED),
MCDI_DWORD(outbuf, GET_LINK_OUT_FLAGS),
MCDI_DWORD(outbuf, GET_LINK_OUT_FCNTL));
}
return !efx_link_state_equal(&efx->link_state, &old_state);
}
......@@ -531,11 +513,8 @@ static void efx_mcdi_phy_get_settings(struct efx_nic *efx, struct ethtool_cmd *e
BUILD_BUG_ON(MC_CMD_GET_LINK_IN_LEN != 0);
rc = efx_mcdi_rpc(efx, MC_CMD_GET_LINK, NULL, 0,
outbuf, sizeof(outbuf), NULL);
if (rc) {
netif_err(efx, hw, efx->net_dev, "%s: failed rc=%d\n",
__func__, rc);
if (rc)
return;
}
ecmd->lp_advertising =
mcdi_to_ethtool_cap(phy_cfg->media,
MCDI_DWORD(outbuf, GET_LINK_OUT_LP_CAP));
......@@ -918,21 +897,29 @@ bool efx_mcdi_mac_check_fault(struct efx_nic *efx)
rc = efx_mcdi_rpc(efx, MC_CMD_GET_LINK, NULL, 0,
outbuf, sizeof(outbuf), &outlength);
if (rc) {
netif_err(efx, hw, efx->net_dev, "%s: failed rc=%d\n",
__func__, rc);
if (rc)
return true;
}
return MCDI_DWORD(outbuf, GET_LINK_OUT_MAC_FAULT) != 0;
}
static int efx_mcdi_mac_stats(struct efx_nic *efx, dma_addr_t dma_addr,
u32 dma_len, int enable, int clear)
enum efx_stats_action {
EFX_STATS_ENABLE,
EFX_STATS_DISABLE,
EFX_STATS_PULL,
};
static int efx_mcdi_mac_stats(struct efx_nic *efx,
enum efx_stats_action action, int clear)
{
MCDI_DECLARE_BUF(inbuf, MC_CMD_MAC_STATS_IN_LEN);
int rc;
int period = enable ? 1000 : 0;
int change = action == EFX_STATS_PULL ? 0 : 1;
int enable = action == EFX_STATS_ENABLE ? 1 : 0;
int period = action == EFX_STATS_ENABLE ? 1000 : 0;
dma_addr_t dma_addr = efx->stats_buffer.dma_addr;
u32 dma_len = action != EFX_STATS_DISABLE ?
MC_CMD_MAC_NSTATS * sizeof(u64) : 0;
BUILD_BUG_ON(MC_CMD_MAC_STATS_OUT_DMA_LEN != 0);
......@@ -940,8 +927,8 @@ static int efx_mcdi_mac_stats(struct efx_nic *efx, dma_addr_t dma_addr,
MCDI_POPULATE_DWORD_7(inbuf, MAC_STATS_IN_CMD,
MAC_STATS_IN_DMA, !!enable,
MAC_STATS_IN_CLEAR, clear,
MAC_STATS_IN_PERIODIC_CHANGE, 1,
MAC_STATS_IN_PERIODIC_ENABLE, !!enable,
MAC_STATS_IN_PERIODIC_CHANGE, change,
MAC_STATS_IN_PERIODIC_ENABLE, enable,
MAC_STATS_IN_PERIODIC_CLEAR, 0,
MAC_STATS_IN_PERIODIC_NOEVENT, 1,
MAC_STATS_IN_PERIOD_MS, period);
......@@ -949,14 +936,6 @@ static int efx_mcdi_mac_stats(struct efx_nic *efx, dma_addr_t dma_addr,
rc = efx_mcdi_rpc(efx, MC_CMD_MAC_STATS, inbuf, sizeof(inbuf),
NULL, 0, NULL);
if (rc)
goto fail;
return 0;
fail:
netif_err(efx, hw, efx->net_dev, "%s: %s failed rc=%d\n",
__func__, enable ? "enable" : "disable", rc);
return rc;
}
......@@ -966,13 +945,29 @@ void efx_mcdi_mac_start_stats(struct efx_nic *efx)
dma_stats[MC_CMD_MAC_GENERATION_END] = EFX_MC_STATS_GENERATION_INVALID;
efx_mcdi_mac_stats(efx, efx->stats_buffer.dma_addr,
MC_CMD_MAC_NSTATS * sizeof(u64), 1, 0);
efx_mcdi_mac_stats(efx, EFX_STATS_ENABLE, 0);
}
void efx_mcdi_mac_stop_stats(struct efx_nic *efx)
{
efx_mcdi_mac_stats(efx, efx->stats_buffer.dma_addr, 0, 0, 0);
efx_mcdi_mac_stats(efx, EFX_STATS_DISABLE, 0);
}
#define EFX_MAC_STATS_WAIT_US 100
#define EFX_MAC_STATS_WAIT_ATTEMPTS 10
void efx_mcdi_mac_pull_stats(struct efx_nic *efx)
{
__le64 *dma_stats = efx->stats_buffer.addr;
int attempts = EFX_MAC_STATS_WAIT_ATTEMPTS;
dma_stats[MC_CMD_MAC_GENERATION_END] = EFX_MC_STATS_GENERATION_INVALID;
efx_mcdi_mac_stats(efx, EFX_STATS_PULL, 0);
while (dma_stats[MC_CMD_MAC_GENERATION_END] ==
EFX_MC_STATS_GENERATION_INVALID &&
attempts-- != 0)
udelay(EFX_MAC_STATS_WAIT_US);
}
int efx_mcdi_port_probe(struct efx_nic *efx)
......@@ -1003,7 +998,7 @@ int efx_mcdi_port_probe(struct efx_nic *efx)
efx->stats_buffer.addr,
(u64)virt_to_phys(efx->stats_buffer.addr));
efx_mcdi_mac_stats(efx, efx->stats_buffer.dma_addr, 0, 0, 1);
efx_mcdi_mac_stats(efx, EFX_STATS_DISABLE, 1);
return 0;
}
......
......@@ -683,6 +683,8 @@ struct vfdi_status;
* @n_channels: Number of channels in use
* @n_rx_channels: Number of channels used for RX (= number of RX queues)
* @n_tx_channels: Number of channels used for TX
* @rx_ip_align: RX DMA address offset to have IP header aligned in
* in accordance with NET_IP_ALIGN
* @rx_dma_len: Current maximum RX DMA length
* @rx_buffer_order: Order (log2) of number of pages for each RX buffer
* @rx_buffer_truesize: Amortised allocation size of an RX buffer,
......@@ -816,6 +818,7 @@ struct efx_nic {
unsigned rss_spread;
unsigned tx_channel_offset;
unsigned n_tx_channels;
unsigned int rx_ip_align;
unsigned int rx_dma_len;
unsigned int rx_buffer_order;
unsigned int rx_buffer_truesize;
......@@ -849,10 +852,14 @@ struct efx_nic {
struct work_struct mac_work;
bool port_enabled;
bool mc_bist_for_other_fn;
bool port_initialized;
struct net_device *net_dev;
struct efx_buffer stats_buffer;
u64 rx_nodesc_drops_total;
u64 rx_nodesc_drops_while_down;
bool rx_nodesc_drops_prev_state;
unsigned int phy_type;
const struct efx_phy_operations *phy_op;
......@@ -956,6 +963,7 @@ struct efx_mtd_partition {
* @update_stats: Update statistics not provided by event handling.
* Either argument may be %NULL.
* @start_stats: Start the regular fetching of statistics
* @pull_stats: Pull stats from the NIC and wait until they arrive.
* @stop_stats: Stop the regular fetching of statistics
* @set_id_led: Set state of identifying LED or revert to automatic function
* @push_irq_moderation: Apply interrupt moderation value
......@@ -1074,6 +1082,7 @@ struct efx_nic_type {
size_t (*update_stats)(struct efx_nic *efx, u64 *full_stats,
struct rtnl_link_stats64 *core_stats);
void (*start_stats)(struct efx_nic *efx);
void (*pull_stats)(struct efx_nic *efx);
void (*stop_stats)(struct efx_nic *efx);
void (*set_id_led)(struct efx_nic *efx, enum efx_led_mode mode);
void (*push_irq_moderation)(struct efx_channel *channel);
......
......@@ -519,3 +519,15 @@ void efx_nic_update_stats(const struct efx_hw_stat_desc *desc, size_t count,
}
}
}
void efx_nic_fix_nodesc_drop_stat(struct efx_nic *efx, u64 *rx_nodesc_drops)
{
/* if down, or this is the first update after coming up */
if (!(efx->net_dev->flags & IFF_UP) || !efx->rx_nodesc_drops_prev_state)
efx->rx_nodesc_drops_while_down +=
*rx_nodesc_drops - efx->rx_nodesc_drops_total;
efx->rx_nodesc_drops_total = *rx_nodesc_drops;
efx->rx_nodesc_drops_prev_state = !!(efx->net_dev->flags & IFF_UP);
*rx_nodesc_drops -= efx->rx_nodesc_drops_while_down;
}
......@@ -554,13 +554,17 @@ int efx_sriov_set_vf_spoofchk(struct net_device *net_dev, int vf,
bool spoofchk);
struct ethtool_ts_info;
void efx_ptp_probe(struct efx_nic *efx);
int efx_ptp_probe(struct efx_nic *efx, struct efx_channel *channel);
void efx_ptp_defer_probe_with_channel(struct efx_nic *efx);
void efx_ptp_remove(struct efx_nic *efx);
int efx_ptp_set_ts_config(struct efx_nic *efx, struct ifreq *ifr);
int efx_ptp_get_ts_config(struct efx_nic *efx, struct ifreq *ifr);
void efx_ptp_get_ts_info(struct efx_nic *efx, struct ethtool_ts_info *ts_info);
bool efx_ptp_is_ptp_tx(struct efx_nic *efx, struct sk_buff *skb);
int efx_ptp_tx(struct efx_nic *efx, struct sk_buff *skb);
void efx_ptp_event(struct efx_nic *efx, efx_qword_t *ev);
void efx_ptp_start_datapath(struct efx_nic *efx);
void efx_ptp_stop_datapath(struct efx_nic *efx);
extern const struct efx_nic_type falcon_a1_nic_type;
extern const struct efx_nic_type falcon_b0_nic_type;
......@@ -773,6 +777,7 @@ size_t efx_nic_describe_stats(const struct efx_hw_stat_desc *desc, size_t count,
void efx_nic_update_stats(const struct efx_hw_stat_desc *desc, size_t count,
const unsigned long *mask, u64 *stats,
const void *dma_buf, bool accumulate);
void efx_nic_fix_nodesc_drop_stat(struct efx_nic *efx, u64 *stat);
#define EFX_MAX_FLUSH_TIME 5000
......
......@@ -214,12 +214,14 @@ struct efx_ptp_timeset {
/**
* struct efx_ptp_data - Precision Time Protocol (PTP) state
* @channel: The PTP channel
* @efx: The NIC context
* @channel: The PTP channel (Siena only)
* @rxq: Receive queue (awaiting timestamps)
* @txq: Transmit queue
* @evt_list: List of MC receive events awaiting packets
* @evt_free_list: List of free events
* @evt_lock: Lock for manipulating evt_list and evt_free_list
* @evt_overflow: Boolean indicating that event list has overflowed
* @rx_evts: Instantiated events (on evt_list and evt_free_list)
* @workwq: Work queue for processing pending PTP operations
* @work: Work task
......@@ -264,12 +266,14 @@ struct efx_ptp_timeset {
* @timeset: Last set of synchronisation statistics.
*/
struct efx_ptp_data {
struct efx_nic *efx;
struct efx_channel *channel;
struct sk_buff_head rxq;
struct sk_buff_head txq;
struct list_head evt_list;
struct list_head evt_free_list;
spinlock_t evt_lock;
bool evt_overflow;
struct efx_ptp_event_rx rx_evts[MAX_RECEIVE_EVENTS];
struct workqueue_struct *workwq;
struct work_struct work;
......@@ -311,15 +315,24 @@ static int efx_phc_enable(struct ptp_clock_info *ptp,
static int efx_ptp_enable(struct efx_nic *efx)
{
MCDI_DECLARE_BUF(inbuf, MC_CMD_PTP_IN_ENABLE_LEN);
MCDI_DECLARE_BUF_OUT_OR_ERR(outbuf, 0);
int rc;
MCDI_SET_DWORD(inbuf, PTP_IN_OP, MC_CMD_PTP_OP_ENABLE);
MCDI_SET_DWORD(inbuf, PTP_IN_PERIPH_ID, 0);
MCDI_SET_DWORD(inbuf, PTP_IN_ENABLE_QUEUE,
efx->ptp_data->channel->channel);
efx->ptp_data->channel ?
efx->ptp_data->channel->channel : 0);
MCDI_SET_DWORD(inbuf, PTP_IN_ENABLE_MODE, efx->ptp_data->mode);
return efx_mcdi_rpc(efx, MC_CMD_PTP, inbuf, sizeof(inbuf),
NULL, 0, NULL);
rc = efx_mcdi_rpc_quiet(efx, MC_CMD_PTP, inbuf, sizeof(inbuf),
outbuf, sizeof(outbuf), NULL);
rc = (rc == -EALREADY) ? 0 : rc;
if (rc)
efx_mcdi_display_error(efx, MC_CMD_PTP,
MC_CMD_PTP_IN_ENABLE_LEN,
outbuf, sizeof(outbuf), rc);
return rc;
}
/* Disable MCDI PTP support.
......@@ -330,11 +343,19 @@ static int efx_ptp_enable(struct efx_nic *efx)
static int efx_ptp_disable(struct efx_nic *efx)
{
MCDI_DECLARE_BUF(inbuf, MC_CMD_PTP_IN_DISABLE_LEN);
MCDI_DECLARE_BUF_OUT_OR_ERR(outbuf, 0);
int rc;
MCDI_SET_DWORD(inbuf, PTP_IN_OP, MC_CMD_PTP_OP_DISABLE);
MCDI_SET_DWORD(inbuf, PTP_IN_PERIPH_ID, 0);
return efx_mcdi_rpc(efx, MC_CMD_PTP, inbuf, sizeof(inbuf),
NULL, 0, NULL);
rc = efx_mcdi_rpc_quiet(efx, MC_CMD_PTP, inbuf, sizeof(inbuf),
outbuf, sizeof(outbuf), NULL);
rc = (rc == -EALREADY) ? 0 : rc;
if (rc)
efx_mcdi_display_error(efx, MC_CMD_PTP,
MC_CMD_PTP_IN_DISABLE_LEN,
outbuf, sizeof(outbuf), rc);
return rc;
}
static void efx_ptp_deliver_rx_queue(struct sk_buff_head *q)
......@@ -635,6 +656,11 @@ static void efx_ptp_drop_time_expired_events(struct efx_nic *efx)
}
}
}
/* If the event overflow flag is set and the event list is now empty
* clear the flag to re-enable the overflow warning message.
*/
if (ptp->evt_overflow && list_empty(&ptp->evt_list))
ptp->evt_overflow = false;
spin_unlock_bh(&ptp->evt_lock);
}
......@@ -676,6 +702,11 @@ static enum ptp_packet_state efx_ptp_match_rx(struct efx_nic *efx,
break;
}
}
/* If the event overflow flag is set and the event list is now empty
* clear the flag to re-enable the overflow warning message.
*/
if (ptp->evt_overflow && list_empty(&ptp->evt_list))
ptp->evt_overflow = false;
spin_unlock_bh(&ptp->evt_lock);
return rc;
......@@ -705,8 +736,9 @@ static bool efx_ptp_process_events(struct efx_nic *efx, struct sk_buff_head *q)
__skb_queue_tail(q, skb);
} else if (time_after(jiffies, match->expiry)) {
match->state = PTP_PACKET_STATE_TIMED_OUT;
netif_warn(efx, rx_err, efx->net_dev,
"PTP packet - no timestamp seen\n");
if (net_ratelimit())
netif_warn(efx, rx_err, efx->net_dev,
"PTP packet - no timestamp seen\n");
__skb_queue_tail(q, skb);
} else {
/* Replace unprocessed entry and stop */
......@@ -726,13 +758,27 @@ static inline void efx_ptp_process_rx(struct efx_nic *efx, struct sk_buff *skb)
local_bh_enable();
}
static int efx_ptp_start(struct efx_nic *efx)
static void efx_ptp_remove_multicast_filters(struct efx_nic *efx)
{
struct efx_ptp_data *ptp = efx->ptp_data;
if (ptp->rxfilter_installed) {
efx_filter_remove_id_safe(efx, EFX_FILTER_PRI_REQUIRED,
ptp->rxfilter_general);
efx_filter_remove_id_safe(efx, EFX_FILTER_PRI_REQUIRED,
ptp->rxfilter_event);
ptp->rxfilter_installed = false;
}
}
static int efx_ptp_insert_multicast_filters(struct efx_nic *efx)
{
struct efx_ptp_data *ptp = efx->ptp_data;
struct efx_filter_spec rxfilter;
int rc;
ptp->reset_required = false;
if (!ptp->channel || ptp->rxfilter_installed)
return 0;
/* Must filter on both event and general ports to ensure
* that there is no packet re-ordering.
......@@ -765,40 +811,53 @@ static int efx_ptp_start(struct efx_nic *efx)
goto fail;
ptp->rxfilter_general = rc;
ptp->rxfilter_installed = true;
return 0;
fail:
efx_filter_remove_id_safe(efx, EFX_FILTER_PRI_REQUIRED,
ptp->rxfilter_event);
return rc;
}
static int efx_ptp_start(struct efx_nic *efx)
{
struct efx_ptp_data *ptp = efx->ptp_data;
int rc;
ptp->reset_required = false;
rc = efx_ptp_insert_multicast_filters(efx);
if (rc)
return rc;
rc = efx_ptp_enable(efx);
if (rc != 0)
goto fail2;
goto fail;
ptp->evt_frag_idx = 0;
ptp->current_adjfreq = 0;
ptp->rxfilter_installed = true;
return 0;
fail2:
efx_filter_remove_id_safe(efx, EFX_FILTER_PRI_REQUIRED,
ptp->rxfilter_general);
fail:
efx_filter_remove_id_safe(efx, EFX_FILTER_PRI_REQUIRED,
ptp->rxfilter_event);
efx_ptp_remove_multicast_filters(efx);
return rc;
}
static int efx_ptp_stop(struct efx_nic *efx)
{
struct efx_ptp_data *ptp = efx->ptp_data;
int rc = efx_ptp_disable(efx);
struct list_head *cursor;
struct list_head *next;
int rc;
if (ptp->rxfilter_installed) {
efx_filter_remove_id_safe(efx, EFX_FILTER_PRI_REQUIRED,
ptp->rxfilter_general);
efx_filter_remove_id_safe(efx, EFX_FILTER_PRI_REQUIRED,
ptp->rxfilter_event);
ptp->rxfilter_installed = false;
}
if (ptp == NULL)
return 0;
rc = efx_ptp_disable(efx);
efx_ptp_remove_multicast_filters(efx);
/* Make sure RX packets are really delivered */
efx_ptp_deliver_rx_queue(&efx->ptp_data->rxq);
......@@ -809,16 +868,24 @@ static int efx_ptp_stop(struct efx_nic *efx)
list_for_each_safe(cursor, next, &efx->ptp_data->evt_list) {
list_move(cursor, &efx->ptp_data->evt_free_list);
}
ptp->evt_overflow = false;
spin_unlock_bh(&efx->ptp_data->evt_lock);
return rc;
}
static int efx_ptp_restart(struct efx_nic *efx)
{
if (efx->ptp_data && efx->ptp_data->enabled)
return efx_ptp_start(efx);
return 0;
}
static void efx_ptp_pps_worker(struct work_struct *work)
{
struct efx_ptp_data *ptp =
container_of(work, struct efx_ptp_data, pps_work);
struct efx_nic *efx = ptp->channel->efx;
struct efx_nic *efx = ptp->efx;
struct ptp_clock_event ptp_evt;
if (efx_ptp_synchronize(efx, PTP_SYNC_ATTEMPTS))
......@@ -835,7 +902,7 @@ static void efx_ptp_worker(struct work_struct *work)
{
struct efx_ptp_data *ptp_data =
container_of(work, struct efx_ptp_data, work);
struct efx_nic *efx = ptp_data->channel->efx;
struct efx_nic *efx = ptp_data->efx;
struct sk_buff *skb;
struct sk_buff_head tempq;
......@@ -859,31 +926,25 @@ static void efx_ptp_worker(struct work_struct *work)
efx_ptp_process_rx(efx, skb);
}
/* Initialise PTP channel and state.
*
* Setting core_index to zero causes the queue to be initialised and doesn't
* overlap with 'rxq0' because ptp.c doesn't use skb_record_rx_queue.
*/
static int efx_ptp_probe_channel(struct efx_channel *channel)
/* Initialise PTP state. */
int efx_ptp_probe(struct efx_nic *efx, struct efx_channel *channel)
{
struct efx_nic *efx = channel->efx;
struct efx_ptp_data *ptp;
int rc = 0;
unsigned int pos;
channel->irq_moderation = 0;
channel->rx_queue.core_index = 0;
ptp = kzalloc(sizeof(struct efx_ptp_data), GFP_KERNEL);
efx->ptp_data = ptp;
if (!efx->ptp_data)
return -ENOMEM;
ptp->efx = efx;
ptp->channel = channel;
rc = efx_nic_alloc_buffer(efx, &ptp->start, sizeof(int), GFP_KERNEL);
if (rc != 0)
goto fail1;
ptp->channel = channel;
skb_queue_head_init(&ptp->rxq);
skb_queue_head_init(&ptp->txq);
ptp->workwq = create_singlethread_workqueue("sfc_ptp");
......@@ -901,6 +962,7 @@ static int efx_ptp_probe_channel(struct efx_channel *channel)
spin_lock_init(&ptp->evt_lock);
for (pos = 0; pos < MAX_RECEIVE_EVENTS; pos++)
list_add(&ptp->rx_evts[pos].link, &ptp->evt_free_list);
ptp->evt_overflow = false;
ptp->phc_clock_info.owner = THIS_MODULE;
snprintf(ptp->phc_clock_info.name,
......@@ -949,14 +1011,27 @@ static int efx_ptp_probe_channel(struct efx_channel *channel)
return rc;
}
static void efx_ptp_remove_channel(struct efx_channel *channel)
/* Initialise PTP channel.
*
* Setting core_index to zero causes the queue to be initialised and doesn't
* overlap with 'rxq0' because ptp.c doesn't use skb_record_rx_queue.
*/
static int efx_ptp_probe_channel(struct efx_channel *channel)
{
struct efx_nic *efx = channel->efx;
channel->irq_moderation = 0;
channel->rx_queue.core_index = 0;
return efx_ptp_probe(efx, channel);
}
void efx_ptp_remove(struct efx_nic *efx)
{
if (!efx->ptp_data)
return;
(void)efx_ptp_disable(channel->efx);
(void)efx_ptp_disable(efx);
cancel_work_sync(&efx->ptp_data->work);
cancel_work_sync(&efx->ptp_data->pps_work);
......@@ -973,6 +1048,11 @@ static void efx_ptp_remove_channel(struct efx_channel *channel)
kfree(efx->ptp_data);
}
static void efx_ptp_remove_channel(struct efx_channel *channel)
{
efx_ptp_remove(channel->efx);
}
static void efx_ptp_get_channel_name(struct efx_channel *channel,
char *buf, size_t len)
{
......@@ -989,7 +1069,11 @@ bool efx_ptp_is_ptp_tx(struct efx_nic *efx, struct sk_buff *skb)
skb->len >= PTP_MIN_LENGTH &&
skb->len <= MC_CMD_PTP_IN_TRANSMIT_PACKET_MAXNUM &&
likely(skb->protocol == htons(ETH_P_IP)) &&
skb_transport_header_was_set(skb) &&
skb_network_header_len(skb) >= sizeof(struct iphdr) &&
ip_hdr(skb)->protocol == IPPROTO_UDP &&
skb_headlen(skb) >=
skb_transport_offset(skb) + sizeof(struct udphdr) &&
udp_hdr(skb)->dest == htons(PTP_EVENT_PORT);
}
......@@ -1106,7 +1190,7 @@ static int efx_ptp_change_mode(struct efx_nic *efx, bool enable_wanted,
{
if ((enable_wanted != efx->ptp_data->enabled) ||
(enable_wanted && (efx->ptp_data->mode != new_mode))) {
int rc;
int rc = 0;
if (enable_wanted) {
/* Change of mode requires disable */
......@@ -1123,7 +1207,8 @@ static int efx_ptp_change_mode(struct efx_nic *efx, bool enable_wanted,
* succeed.
*/
efx->ptp_data->mode = new_mode;
rc = efx_ptp_start(efx);
if (netif_running(efx->net_dev))
rc = efx_ptp_start(efx);
if (rc == 0) {
rc = efx_ptp_synchronize(efx,
PTP_SYNC_ATTEMPTS * 2);
......@@ -1304,8 +1389,13 @@ static void ptp_event_rx(struct efx_nic *efx, struct efx_ptp_data *ptp)
list_add_tail(&evt->link, &ptp->evt_list);
queue_work(ptp->workwq, &ptp->work);
} else {
netif_err(efx, rx_err, efx->net_dev, "No free PTP event");
} else if (!ptp->evt_overflow) {
/* Log a warning message and set the event overflow flag.
* The message won't be logged again until the event queue
* becomes empty.
*/
netif_err(efx, rx_err, efx->net_dev, "PTP event queue overflow\n");
ptp->evt_overflow = true;
}
spin_unlock_bh(&ptp->evt_lock);
}
......@@ -1374,7 +1464,7 @@ static int efx_phc_adjfreq(struct ptp_clock_info *ptp, s32 delta)
struct efx_ptp_data *ptp_data = container_of(ptp,
struct efx_ptp_data,
phc_clock_info);
struct efx_nic *efx = ptp_data->channel->efx;
struct efx_nic *efx = ptp_data->efx;
MCDI_DECLARE_BUF(inadj, MC_CMD_PTP_IN_ADJUST_LEN);
s64 adjustment_ns;
int rc;
......@@ -1398,7 +1488,7 @@ static int efx_phc_adjfreq(struct ptp_clock_info *ptp, s32 delta)
if (rc != 0)
return rc;
ptp_data->current_adjfreq = delta;
ptp_data->current_adjfreq = adjustment_ns;
return 0;
}
......@@ -1407,13 +1497,13 @@ static int efx_phc_adjtime(struct ptp_clock_info *ptp, s64 delta)
struct efx_ptp_data *ptp_data = container_of(ptp,
struct efx_ptp_data,
phc_clock_info);
struct efx_nic *efx = ptp_data->channel->efx;
struct efx_nic *efx = ptp_data->efx;
struct timespec delta_ts = ns_to_timespec(delta);
MCDI_DECLARE_BUF(inbuf, MC_CMD_PTP_IN_ADJUST_LEN);
MCDI_SET_DWORD(inbuf, PTP_IN_OP, MC_CMD_PTP_OP_ADJUST);
MCDI_SET_DWORD(inbuf, PTP_IN_PERIPH_ID, 0);
MCDI_SET_QWORD(inbuf, PTP_IN_ADJUST_FREQ, 0);
MCDI_SET_QWORD(inbuf, PTP_IN_ADJUST_FREQ, ptp_data->current_adjfreq);
MCDI_SET_DWORD(inbuf, PTP_IN_ADJUST_SECONDS, (u32)delta_ts.tv_sec);
MCDI_SET_DWORD(inbuf, PTP_IN_ADJUST_NANOSECONDS, (u32)delta_ts.tv_nsec);
return efx_mcdi_rpc(efx, MC_CMD_PTP, inbuf, sizeof(inbuf),
......@@ -1425,7 +1515,7 @@ static int efx_phc_gettime(struct ptp_clock_info *ptp, struct timespec *ts)
struct efx_ptp_data *ptp_data = container_of(ptp,
struct efx_ptp_data,
phc_clock_info);
struct efx_nic *efx = ptp_data->channel->efx;
struct efx_nic *efx = ptp_data->efx;
MCDI_DECLARE_BUF(inbuf, MC_CMD_PTP_IN_READ_NIC_TIME_LEN);
MCDI_DECLARE_BUF(outbuf, MC_CMD_PTP_OUT_READ_NIC_TIME_LEN);
int rc;
......@@ -1491,7 +1581,7 @@ static const struct efx_channel_type efx_ptp_channel_type = {
.keep_eventq = false,
};
void efx_ptp_probe(struct efx_nic *efx)
void efx_ptp_defer_probe_with_channel(struct efx_nic *efx)
{
/* Check whether PTP is implemented on this NIC. The DISABLE
* operation will succeed if and only if it is implemented.
......@@ -1500,3 +1590,14 @@ void efx_ptp_probe(struct efx_nic *efx)
efx->extra_channel_type[EFX_EXTRA_CHANNEL_PTP] =
&efx_ptp_channel_type;
}
void efx_ptp_start_datapath(struct efx_nic *efx)
{
if (efx_ptp_restart(efx))
netif_err(efx, drv, efx->net_dev, "Failed to restart PTP.\n");
}
void efx_ptp_stop_datapath(struct efx_nic *efx)
{
efx_ptp_stop(efx);
}
......@@ -94,7 +94,7 @@ static inline void efx_sync_rx_buffer(struct efx_nic *efx,
void efx_rx_config_page_split(struct efx_nic *efx)
{
efx->rx_page_buf_step = ALIGN(efx->rx_dma_len + NET_IP_ALIGN,
efx->rx_page_buf_step = ALIGN(efx->rx_dma_len + efx->rx_ip_align,
EFX_RX_BUF_ALIGNMENT);
efx->rx_bufs_per_page = efx->rx_buffer_order ? 1 :
((PAGE_SIZE - sizeof(struct efx_rx_page_state)) /
......@@ -149,7 +149,7 @@ static struct page *efx_reuse_page(struct efx_rx_queue *rx_queue)
* 0 on success. If a single page can be used for multiple buffers,
* then the page will either be inserted fully, or not at all.
*/
static int efx_init_rx_buffers(struct efx_rx_queue *rx_queue)
static int efx_init_rx_buffers(struct efx_rx_queue *rx_queue, bool atomic)
{
struct efx_nic *efx = rx_queue->efx;
struct efx_rx_buffer *rx_buf;
......@@ -163,7 +163,8 @@ static int efx_init_rx_buffers(struct efx_rx_queue *rx_queue)
do {
page = efx_reuse_page(rx_queue);
if (page == NULL) {
page = alloc_pages(__GFP_COLD | __GFP_COMP | GFP_ATOMIC,
page = alloc_pages(__GFP_COLD | __GFP_COMP |
(atomic ? GFP_ATOMIC : GFP_KERNEL),
efx->rx_buffer_order);
if (unlikely(page == NULL))
return -ENOMEM;
......@@ -189,9 +190,9 @@ static int efx_init_rx_buffers(struct efx_rx_queue *rx_queue)
do {
index = rx_queue->added_count & rx_queue->ptr_mask;
rx_buf = efx_rx_buffer(rx_queue, index);
rx_buf->dma_addr = dma_addr + NET_IP_ALIGN;
rx_buf->dma_addr = dma_addr + efx->rx_ip_align;
rx_buf->page = page;
rx_buf->page_offset = page_offset + NET_IP_ALIGN;
rx_buf->page_offset = page_offset + efx->rx_ip_align;
rx_buf->len = efx->rx_dma_len;
rx_buf->flags = 0;
++rx_queue->added_count;
......@@ -321,7 +322,7 @@ static void efx_discard_rx_packet(struct efx_channel *channel,
* this means this function must run from the NAPI handler, or be called
* when NAPI is disabled.
*/
void efx_fast_push_rx_descriptors(struct efx_rx_queue *rx_queue)
void efx_fast_push_rx_descriptors(struct efx_rx_queue *rx_queue, bool atomic)
{
struct efx_nic *efx = rx_queue->efx;
unsigned int fill_level, batch_size;
......@@ -354,7 +355,7 @@ void efx_fast_push_rx_descriptors(struct efx_rx_queue *rx_queue)
do {
rc = efx_init_rx_buffers(rx_queue);
rc = efx_init_rx_buffers(rx_queue, atomic);
if (unlikely(rc)) {
/* Ensure that we don't leave the rx queue empty */
if (rx_queue->added_count == rx_queue->removed_count)
......
......@@ -722,7 +722,7 @@ int efx_selftest(struct efx_nic *efx, struct efx_self_tests *tests,
return rc_reset;
}
if ((tests->registers < 0) && !rc_test)
if ((tests->memory < 0 || tests->registers < 0) && !rc_test)
rc_test = -EIO;
}
......
......@@ -38,6 +38,7 @@ struct efx_self_tests {
int eventq_dma[EFX_MAX_CHANNELS];
int eventq_int[EFX_MAX_CHANNELS];
/* offline tests */
int memory;
int registers;
int phy_ext[EFX_MAX_PHY_TESTS];
struct efx_loopback_self_tests loopback[LOOPBACK_TEST_MAX + 1];
......
......@@ -259,7 +259,7 @@ static int siena_probe_nic(struct efx_nic *efx)
goto fail5;
efx_sriov_probe(efx);
efx_ptp_probe(efx);
efx_ptp_defer_probe_with_channel(efx);
return 0;
......@@ -458,6 +458,8 @@ static int siena_try_update_nic_stats(struct efx_nic *efx)
return -EAGAIN;
/* Update derived statistics */
efx_nic_fix_nodesc_drop_stat(efx,
&stats[SIENA_STAT_rx_nodesc_drop_cnt]);
efx_update_diff_stat(&stats[SIENA_STAT_tx_good_bytes],
stats[SIENA_STAT_tx_bytes] -
stats[SIENA_STAT_tx_bad_bytes]);
......@@ -878,6 +880,7 @@ const struct efx_nic_type siena_a0_nic_type = {
.describe_stats = siena_describe_nic_stats,
.update_stats = siena_update_nic_stats,
.start_stats = efx_mcdi_mac_start_stats,
.pull_stats = efx_mcdi_mac_pull_stats,
.stop_stats = efx_mcdi_mac_stop_stats,
.set_id_led = efx_mcdi_set_id_led,
.push_irq_moderation = siena_push_irq_moderation,
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册