diff options
-rw-r--r-- | drivers/net/sfc/falcon.c | 2 | ||||
-rw-r--r-- | drivers/net/sfc/mcdi.h | 1 | ||||
-rw-r--r-- | drivers/net/sfc/mcdi_mac.c | 4 | ||||
-rw-r--r-- | drivers/net/sfc/net_driver.h | 6 | ||||
-rw-r--r-- | drivers/net/sfc/nic.c | 21 | ||||
-rw-r--r-- | drivers/net/sfc/nic.h | 2 | ||||
-rw-r--r-- | drivers/net/sfc/siena.c | 15 |
7 files changed, 46 insertions, 5 deletions
diff --git a/drivers/net/sfc/falcon.c b/drivers/net/sfc/falcon.c index 60176e873d6..19b996b33d4 100644 --- a/drivers/net/sfc/falcon.c +++ b/drivers/net/sfc/falcon.c @@ -1714,6 +1714,7 @@ const struct efx_nic_type falcon_a1_nic_type = { .remove_port = falcon_remove_port, .handle_global_event = falcon_handle_global_event, .prepare_flush = falcon_prepare_flush, + .finish_flush = efx_port_dummy_op_void, .update_stats = falcon_update_nic_stats, .start_stats = falcon_start_nic_stats, .stop_stats = falcon_stop_nic_stats, @@ -1755,6 +1756,7 @@ const struct efx_nic_type falcon_b0_nic_type = { .remove_port = falcon_remove_port, .handle_global_event = falcon_handle_global_event, .prepare_flush = falcon_prepare_flush, + .finish_flush = efx_port_dummy_op_void, .update_stats = falcon_update_nic_stats, .start_stats = falcon_start_nic_stats, .stop_stats = falcon_stop_nic_stats, diff --git a/drivers/net/sfc/mcdi.h b/drivers/net/sfc/mcdi.h index aced2a7856f..b61eea04616 100644 --- a/drivers/net/sfc/mcdi.h +++ b/drivers/net/sfc/mcdi.h @@ -126,5 +126,6 @@ extern int efx_mcdi_wol_filter_set_magic(struct efx_nic *efx, extern int efx_mcdi_wol_filter_get_magic(struct efx_nic *efx, int *id_out); extern int efx_mcdi_wol_filter_remove(struct efx_nic *efx, int id); extern int efx_mcdi_wol_filter_reset(struct efx_nic *efx); +extern int efx_mcdi_set_mac(struct efx_nic *efx); #endif /* EFX_MCDI_H */ diff --git a/drivers/net/sfc/mcdi_mac.c b/drivers/net/sfc/mcdi_mac.c index 50c20777a56..da269d7076c 100644 --- a/drivers/net/sfc/mcdi_mac.c +++ b/drivers/net/sfc/mcdi_mac.c @@ -13,7 +13,7 @@ #include "mcdi.h" #include "mcdi_pcol.h" -static int efx_mcdi_set_mac(struct efx_nic *efx) +int efx_mcdi_set_mac(struct efx_nic *efx) { u32 reject, fcntl; u8 cmdbytes[MC_CMD_SET_MAC_IN_LEN]; @@ -45,6 +45,8 @@ static int efx_mcdi_set_mac(struct efx_nic *efx) } if (efx->wanted_fc & EFX_FC_AUTO) fcntl = MC_CMD_FCNTL_AUTO; + if (efx->fc_disable) + fcntl = MC_CMD_FCNTL_OFF; MCDI_SET_DWORD(cmdbytes, SET_MAC_IN_FCNTL, fcntl); diff --git a/drivers/net/sfc/net_driver.h b/drivers/net/sfc/net_driver.h index e8d5f03a89f..47aff8ec720 100644 --- a/drivers/net/sfc/net_driver.h +++ b/drivers/net/sfc/net_driver.h @@ -690,6 +690,9 @@ struct efx_filter_state; * @promiscuous: Promiscuous flag. Protected by netif_tx_lock. * @multicast_hash: Multicast hash table * @wanted_fc: Wanted flow control flags + * @fc_disable: When non-zero flow control is disabled. Typically used to + * ensure that network back pressure doesn't delay dma queue flushes. + * Serialised by the rtnl lock. * @mac_work: Work item for changing MAC promiscuity and multicast hash * @loopback_mode: Loopback status * @loopback_modes: Supported loopback mode bitmask @@ -783,6 +786,7 @@ struct efx_nic { bool promiscuous; union efx_multicast_hash multicast_hash; u8 wanted_fc; + unsigned fc_disable; atomic_t rx_reset; enum efx_loopback_mode loopback_mode; @@ -834,6 +838,7 @@ static inline unsigned int efx_port_num(struct efx_nic *efx) * @remove_port: Free resources allocated by probe_port() * @handle_global_event: Handle a "global" event (may be %NULL) * @prepare_flush: Prepare the hardware for flushing the DMA queues + * @finish_flush: Clean up after flushing the DMA queues * @update_stats: Update statistics not provided by event handling * @start_stats: Start the regular fetching of statistics * @stop_stats: Stop the regular fetching of statistics @@ -879,6 +884,7 @@ struct efx_nic_type { void (*remove_port)(struct efx_nic *efx); bool (*handle_global_event)(struct efx_channel *channel, efx_qword_t *); void (*prepare_flush)(struct efx_nic *efx); + void (*finish_flush)(struct efx_nic *efx); void (*update_stats)(struct efx_nic *efx); void (*start_stats)(struct efx_nic *efx); void (*stop_stats)(struct efx_nic *efx); diff --git a/drivers/net/sfc/nic.c b/drivers/net/sfc/nic.c index 5ac9fa2cd3b..854df4e7d55 100644 --- a/drivers/net/sfc/nic.c +++ b/drivers/net/sfc/nic.c @@ -1260,13 +1260,27 @@ int efx_nic_flush_queues(struct efx_nic *efx) } efx_for_each_possible_channel_tx_queue(tx_queue, channel) { if (tx_queue->initialised && - tx_queue->flushed != FLUSH_DONE) - ++tx_pending; + tx_queue->flushed != FLUSH_DONE) { + efx_oword_t txd_ptr_tbl; + + efx_reado_table(efx, &txd_ptr_tbl, + FR_BZ_TX_DESC_PTR_TBL, + tx_queue->queue); + if (EFX_OWORD_FIELD(txd_ptr_tbl, + FRF_AZ_TX_DESCQ_FLUSH) || + EFX_OWORD_FIELD(txd_ptr_tbl, + FRF_AZ_TX_DESCQ_EN)) + ++tx_pending; + else + tx_queue->flushed = FLUSH_DONE; + } } } - if (rx_pending == 0 && tx_pending == 0) + if (rx_pending == 0 && tx_pending == 0) { + efx->type->finish_flush(efx); return 0; + } msleep(EFX_FLUSH_INTERVAL); efx_poll_flush_events(efx); @@ -1292,6 +1306,7 @@ int efx_nic_flush_queues(struct efx_nic *efx) } } + efx->type->finish_flush(efx); return -ETIMEDOUT; } diff --git a/drivers/net/sfc/nic.h b/drivers/net/sfc/nic.h index d2405ceb253..8a2c4f5aa29 100644 --- a/drivers/net/sfc/nic.h +++ b/drivers/net/sfc/nic.h @@ -211,6 +211,8 @@ extern void falcon_irq_ack_a1(struct efx_nic *efx); /* Global Resources */ extern int efx_nic_flush_queues(struct efx_nic *efx); +extern void siena_prepare_flush(struct efx_nic *efx); +extern void siena_finish_flush(struct efx_nic *efx); extern void falcon_start_nic_stats(struct efx_nic *efx); extern void falcon_stop_nic_stats(struct efx_nic *efx); extern void falcon_setup_xaui(struct efx_nic *efx); diff --git a/drivers/net/sfc/siena.c b/drivers/net/sfc/siena.c index 407f50bf2fc..062494a5097 100644 --- a/drivers/net/sfc/siena.c +++ b/drivers/net/sfc/siena.c @@ -135,6 +135,18 @@ static void siena_remove_port(struct efx_nic *efx) efx_nic_free_buffer(efx, &efx->stats_buffer); } +void siena_prepare_flush(struct efx_nic *efx) +{ + if (efx->fc_disable++ == 0) + efx_mcdi_set_mac(efx); +} + +void siena_finish_flush(struct efx_nic *efx) +{ + if (--efx->fc_disable == 0) + efx_mcdi_set_mac(efx); +} + static const struct efx_nic_register_test siena_register_tests[] = { { FR_AZ_ADR_REGION, EFX_OWORD32(0x0003FFFF, 0x0003FFFF, 0x0003FFFF, 0x0003FFFF) }, @@ -590,7 +602,8 @@ const struct efx_nic_type siena_a0_nic_type = { .reset = siena_reset_hw, .probe_port = siena_probe_port, .remove_port = siena_remove_port, - .prepare_flush = efx_port_dummy_op_void, + .prepare_flush = siena_prepare_flush, + .finish_flush = siena_finish_flush, .update_stats = siena_update_nic_stats, .start_stats = siena_start_nic_stats, .stop_stats = siena_stop_nic_stats, |