Commit 85be21bd authored by David S. Miller's avatar David S. Miller

Merge branch 'sfc-SFN8000-support-improvements'

Bert Kenward says:

====================
sfc: SFN8000 support improvements

This series improves support for the recently released SFN8000 series
of adapters. Specifically, it retrieves interrupt moderation timer
settings directly from the adapter and uses those settings. It also
uses a new event queue initialisation interface, allowing specification
of a performance objective rather than enabling individual flags.
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents e3e9652a d95e329a
This diff is collapsed.
...@@ -281,6 +281,27 @@ static int efx_process_channel(struct efx_channel *channel, int budget) ...@@ -281,6 +281,27 @@ static int efx_process_channel(struct efx_channel *channel, int budget)
* NAPI guarantees serialisation of polls of the same device, which * NAPI guarantees serialisation of polls of the same device, which
* provides the guarantee required by efx_process_channel(). * provides the guarantee required by efx_process_channel().
*/ */
static void efx_update_irq_mod(struct efx_nic *efx, struct efx_channel *channel)
{
int step = efx->irq_mod_step_us;
if (channel->irq_mod_score < irq_adapt_low_thresh) {
if (channel->irq_moderation_us > step) {
channel->irq_moderation_us -= step;
efx->type->push_irq_moderation(channel);
}
} else if (channel->irq_mod_score > irq_adapt_high_thresh) {
if (channel->irq_moderation_us <
efx->irq_rx_moderation_us) {
channel->irq_moderation_us += step;
efx->type->push_irq_moderation(channel);
}
}
channel->irq_count = 0;
channel->irq_mod_score = 0;
}
static int efx_poll(struct napi_struct *napi, int budget) static int efx_poll(struct napi_struct *napi, int budget)
{ {
struct efx_channel *channel = struct efx_channel *channel =
...@@ -301,22 +322,7 @@ static int efx_poll(struct napi_struct *napi, int budget) ...@@ -301,22 +322,7 @@ static int efx_poll(struct napi_struct *napi, int budget)
if (efx_channel_has_rx_queue(channel) && if (efx_channel_has_rx_queue(channel) &&
efx->irq_rx_adaptive && efx->irq_rx_adaptive &&
unlikely(++channel->irq_count == 1000)) { unlikely(++channel->irq_count == 1000)) {
if (unlikely(channel->irq_mod_score < efx_update_irq_mod(efx, channel);
irq_adapt_low_thresh)) {
if (channel->irq_moderation > 1) {
channel->irq_moderation -= 1;
efx->type->push_irq_moderation(channel);
}
} else if (unlikely(channel->irq_mod_score >
irq_adapt_high_thresh)) {
if (channel->irq_moderation <
efx->irq_rx_moderation) {
channel->irq_moderation += 1;
efx->type->push_irq_moderation(channel);
}
}
channel->irq_count = 0;
channel->irq_mod_score = 0;
} }
efx_filter_rfs_expire(channel); efx_filter_rfs_expire(channel);
...@@ -1703,6 +1709,7 @@ static int efx_probe_nic(struct efx_nic *efx) ...@@ -1703,6 +1709,7 @@ static int efx_probe_nic(struct efx_nic *efx)
netif_set_real_num_rx_queues(efx->net_dev, efx->n_rx_channels); netif_set_real_num_rx_queues(efx->net_dev, efx->n_rx_channels);
/* Initialise the interrupt moderation settings */ /* Initialise the interrupt moderation settings */
efx->irq_mod_step_us = DIV_ROUND_UP(efx->timer_quantum_ns, 1000);
efx_init_irq_moderation(efx, tx_irq_mod_usec, rx_irq_mod_usec, true, efx_init_irq_moderation(efx, tx_irq_mod_usec, rx_irq_mod_usec, true,
true); true);
...@@ -1949,14 +1956,21 @@ static void efx_remove_all(struct efx_nic *efx) ...@@ -1949,14 +1956,21 @@ static void efx_remove_all(struct efx_nic *efx)
* Interrupt moderation * Interrupt moderation
* *
**************************************************************************/ **************************************************************************/
unsigned int efx_usecs_to_ticks(struct efx_nic *efx, unsigned int usecs)
static unsigned int irq_mod_ticks(unsigned int usecs, unsigned int quantum_ns)
{ {
if (usecs == 0) if (usecs == 0)
return 0; return 0;
if (usecs * 1000 < quantum_ns) if (usecs * 1000 < efx->timer_quantum_ns)
return 1; /* never round down to 0 */ return 1; /* never round down to 0 */
return usecs * 1000 / quantum_ns; return usecs * 1000 / efx->timer_quantum_ns;
}
unsigned int efx_ticks_to_usecs(struct efx_nic *efx, unsigned int ticks)
{
/* We must round up when converting ticks to microseconds
* because we round down when converting the other way.
*/
return DIV_ROUND_UP(ticks * efx->timer_quantum_ns, 1000);
} }
/* Set interrupt moderation parameters */ /* Set interrupt moderation parameters */
...@@ -1965,21 +1979,16 @@ int efx_init_irq_moderation(struct efx_nic *efx, unsigned int tx_usecs, ...@@ -1965,21 +1979,16 @@ int efx_init_irq_moderation(struct efx_nic *efx, unsigned int tx_usecs,
bool rx_may_override_tx) bool rx_may_override_tx)
{ {
struct efx_channel *channel; struct efx_channel *channel;
unsigned int irq_mod_max = DIV_ROUND_UP(efx->type->timer_period_max * unsigned int timer_max_us;
efx->timer_quantum_ns,
1000);
unsigned int tx_ticks;
unsigned int rx_ticks;
EFX_ASSERT_RESET_SERIALISED(efx); EFX_ASSERT_RESET_SERIALISED(efx);
if (tx_usecs > irq_mod_max || rx_usecs > irq_mod_max) timer_max_us = efx->timer_max_ns / 1000;
return -EINVAL;
tx_ticks = irq_mod_ticks(tx_usecs, efx->timer_quantum_ns); if (tx_usecs > timer_max_us || rx_usecs > timer_max_us)
rx_ticks = irq_mod_ticks(rx_usecs, efx->timer_quantum_ns); return -EINVAL;
if (tx_ticks != rx_ticks && efx->tx_channel_offset == 0 && if (tx_usecs != rx_usecs && efx->tx_channel_offset == 0 &&
!rx_may_override_tx) { !rx_may_override_tx) {
netif_err(efx, drv, efx->net_dev, "Channels are shared. " netif_err(efx, drv, efx->net_dev, "Channels are shared. "
"RX and TX IRQ moderation must be equal\n"); "RX and TX IRQ moderation must be equal\n");
...@@ -1987,12 +1996,12 @@ int efx_init_irq_moderation(struct efx_nic *efx, unsigned int tx_usecs, ...@@ -1987,12 +1996,12 @@ int efx_init_irq_moderation(struct efx_nic *efx, unsigned int tx_usecs,
} }
efx->irq_rx_adaptive = rx_adaptive; efx->irq_rx_adaptive = rx_adaptive;
efx->irq_rx_moderation = rx_ticks; efx->irq_rx_moderation_us = rx_usecs;
efx_for_each_channel(channel, efx) { efx_for_each_channel(channel, efx) {
if (efx_channel_has_rx_queue(channel)) if (efx_channel_has_rx_queue(channel))
channel->irq_moderation = rx_ticks; channel->irq_moderation_us = rx_usecs;
else if (efx_channel_has_tx_queues(channel)) else if (efx_channel_has_tx_queues(channel))
channel->irq_moderation = tx_ticks; channel->irq_moderation_us = tx_usecs;
} }
return 0; return 0;
...@@ -2001,26 +2010,21 @@ int efx_init_irq_moderation(struct efx_nic *efx, unsigned int tx_usecs, ...@@ -2001,26 +2010,21 @@ int efx_init_irq_moderation(struct efx_nic *efx, unsigned int tx_usecs,
void efx_get_irq_moderation(struct efx_nic *efx, unsigned int *tx_usecs, void efx_get_irq_moderation(struct efx_nic *efx, unsigned int *tx_usecs,
unsigned int *rx_usecs, bool *rx_adaptive) unsigned int *rx_usecs, bool *rx_adaptive)
{ {
/* We must round up when converting ticks to microseconds
* because we round down when converting the other way.
*/
*rx_adaptive = efx->irq_rx_adaptive; *rx_adaptive = efx->irq_rx_adaptive;
*rx_usecs = DIV_ROUND_UP(efx->irq_rx_moderation * *rx_usecs = efx->irq_rx_moderation_us;
efx->timer_quantum_ns,
1000);
/* If channels are shared between RX and TX, so is IRQ /* If channels are shared between RX and TX, so is IRQ
* moderation. Otherwise, IRQ moderation is the same for all * moderation. Otherwise, IRQ moderation is the same for all
* TX channels and is not adaptive. * TX channels and is not adaptive.
*/ */
if (efx->tx_channel_offset == 0) if (efx->tx_channel_offset == 0) {
*tx_usecs = *rx_usecs; *tx_usecs = *rx_usecs;
else } else {
*tx_usecs = DIV_ROUND_UP( struct efx_channel *tx_channel;
efx->channel[efx->tx_channel_offset]->irq_moderation *
efx->timer_quantum_ns, tx_channel = efx->channel[efx->tx_channel_offset];
1000); *tx_usecs = tx_channel->irq_moderation_us;
}
} }
/************************************************************************** /**************************************************************************
......
...@@ -204,6 +204,8 @@ int efx_try_recovery(struct efx_nic *efx); ...@@ -204,6 +204,8 @@ int efx_try_recovery(struct efx_nic *efx);
/* Global */ /* Global */
void efx_schedule_reset(struct efx_nic *efx, enum reset_type type); void efx_schedule_reset(struct efx_nic *efx, enum reset_type type);
unsigned int efx_usecs_to_ticks(struct efx_nic *efx, unsigned int usecs);
unsigned int efx_ticks_to_usecs(struct efx_nic *efx, unsigned int ticks);
int efx_init_irq_moderation(struct efx_nic *efx, unsigned int tx_usecs, int efx_init_irq_moderation(struct efx_nic *efx, unsigned int tx_usecs,
unsigned int rx_usecs, bool rx_adaptive, unsigned int rx_usecs, bool rx_adaptive,
bool rx_may_override_tx); bool rx_may_override_tx);
......
...@@ -378,12 +378,15 @@ static void falcon_push_irq_moderation(struct efx_channel *channel) ...@@ -378,12 +378,15 @@ static void falcon_push_irq_moderation(struct efx_channel *channel)
struct efx_nic *efx = channel->efx; struct efx_nic *efx = channel->efx;
/* Set timer register */ /* Set timer register */
if (channel->irq_moderation) { if (channel->irq_moderation_us) {
unsigned int ticks;
ticks = efx_usecs_to_ticks(efx, channel->irq_moderation_us);
EFX_POPULATE_DWORD_2(timer_cmd, EFX_POPULATE_DWORD_2(timer_cmd,
FRF_AB_TC_TIMER_MODE, FRF_AB_TC_TIMER_MODE,
FFE_BB_TIMER_MODE_INT_HLDOFF, FFE_BB_TIMER_MODE_INT_HLDOFF,
FRF_AB_TC_TIMER_VAL, FRF_AB_TC_TIMER_VAL,
channel->irq_moderation - 1); ticks - 1);
} else { } else {
EFX_POPULATE_DWORD_2(timer_cmd, EFX_POPULATE_DWORD_2(timer_cmd,
FRF_AB_TC_TIMER_MODE, FRF_AB_TC_TIMER_MODE,
...@@ -2373,6 +2376,8 @@ static int falcon_probe_nic(struct efx_nic *efx) ...@@ -2373,6 +2376,8 @@ static int falcon_probe_nic(struct efx_nic *efx)
EFX_MAX_CHANNELS); EFX_MAX_CHANNELS);
efx->max_tx_channels = efx->max_channels; efx->max_tx_channels = efx->max_channels;
efx->timer_quantum_ns = 4968; /* 621 cycles */ efx->timer_quantum_ns = 4968; /* 621 cycles */
efx->timer_max_ns = efx->type->timer_period_max *
efx->timer_quantum_ns;
/* Initialise I2C adapter */ /* Initialise I2C adapter */
board = falcon_board(efx); board = falcon_board(efx);
......
...@@ -548,7 +548,10 @@ static bool efx_mcdi_complete_async(struct efx_mcdi_iface *mcdi, bool timeout) ...@@ -548,7 +548,10 @@ static bool efx_mcdi_complete_async(struct efx_mcdi_iface *mcdi, bool timeout)
efx_mcdi_display_error(efx, async->cmd, async->inlen, errbuf, efx_mcdi_display_error(efx, async->cmd, async->inlen, errbuf,
err_len, rc); err_len, rc);
} }
async->complete(efx, async->cookie, rc, outbuf, data_len);
if (async->complete)
async->complete(efx, async->cookie, rc, outbuf,
min(async->outlen, data_len));
kfree(async); kfree(async);
efx_mcdi_release(mcdi); efx_mcdi_release(mcdi);
......
This diff is collapsed.
...@@ -392,7 +392,7 @@ enum efx_sync_events_state { ...@@ -392,7 +392,7 @@ enum efx_sync_events_state {
* @eventq_init: Event queue initialised flag * @eventq_init: Event queue initialised flag
* @enabled: Channel enabled indicator * @enabled: Channel enabled indicator
* @irq: IRQ number (MSI and MSI-X only) * @irq: IRQ number (MSI and MSI-X only)
* @irq_moderation: IRQ moderation value (in hardware ticks) * @irq_moderation_us: IRQ moderation value (in microseconds)
* @napi_dev: Net device used with NAPI * @napi_dev: Net device used with NAPI
* @napi_str: NAPI control structure * @napi_str: NAPI control structure
* @state: state for NAPI vs busy polling * @state: state for NAPI vs busy polling
...@@ -433,7 +433,7 @@ struct efx_channel { ...@@ -433,7 +433,7 @@ struct efx_channel {
bool eventq_init; bool eventq_init;
bool enabled; bool enabled;
int irq; int irq;
unsigned int irq_moderation; unsigned int irq_moderation_us;
struct net_device *napi_dev; struct net_device *napi_dev;
struct napi_struct napi_str; struct napi_struct napi_str;
#ifdef CONFIG_NET_RX_BUSY_POLL #ifdef CONFIG_NET_RX_BUSY_POLL
...@@ -810,8 +810,10 @@ struct vfdi_status; ...@@ -810,8 +810,10 @@ struct vfdi_status;
* @membase: Memory BAR value * @membase: Memory BAR value
* @interrupt_mode: Interrupt mode * @interrupt_mode: Interrupt mode
* @timer_quantum_ns: Interrupt timer quantum, in nanoseconds * @timer_quantum_ns: Interrupt timer quantum, in nanoseconds
* @timer_max_ns: Interrupt timer maximum value, in nanoseconds
* @irq_rx_adaptive: Adaptive IRQ moderation enabled for RX event queues * @irq_rx_adaptive: Adaptive IRQ moderation enabled for RX event queues
* @irq_rx_moderation: IRQ moderation time for RX event queues * @irq_rx_mod_step_us: Step size for IRQ moderation for RX event queues
* @irq_rx_moderation_us: IRQ moderation time for RX event queues
* @msg_enable: Log message enable flags * @msg_enable: Log message enable flags
* @state: Device state number (%STATE_*). Serialised by the rtnl_lock. * @state: Device state number (%STATE_*). Serialised by the rtnl_lock.
* @reset_pending: Bitmask for pending resets * @reset_pending: Bitmask for pending resets
...@@ -940,8 +942,10 @@ struct efx_nic { ...@@ -940,8 +942,10 @@ struct efx_nic {
enum efx_int_mode interrupt_mode; enum efx_int_mode interrupt_mode;
unsigned int timer_quantum_ns; unsigned int timer_quantum_ns;
unsigned int timer_max_ns;
bool irq_rx_adaptive; bool irq_rx_adaptive;
unsigned int irq_rx_moderation; unsigned int irq_mod_step_us;
unsigned int irq_rx_moderation_us;
u32 msg_enable; u32 msg_enable;
enum nic_state state; enum nic_state state;
......
...@@ -507,10 +507,13 @@ enum { ...@@ -507,10 +507,13 @@ enum {
* @stats: Hardware statistics * @stats: Hardware statistics
* @workaround_35388: Flag: firmware supports workaround for bug 35388 * @workaround_35388: Flag: firmware supports workaround for bug 35388
* @workaround_26807: Flag: firmware supports workaround for bug 26807 * @workaround_26807: Flag: firmware supports workaround for bug 26807
* @workaround_61265: Flag: firmware supports workaround for bug 61265
* @must_check_datapath_caps: Flag: @datapath_caps needs to be revalidated * @must_check_datapath_caps: Flag: @datapath_caps needs to be revalidated
* after MC reboot * after MC reboot
* @datapath_caps: Capabilities of datapath firmware (FLAGS1 field of * @datapath_caps: Capabilities of datapath firmware (FLAGS1 field of
* %MC_CMD_GET_CAPABILITIES response) * %MC_CMD_GET_CAPABILITIES response)
* @datapath_caps2: Further Capabilities of datapath firmware (FLAGS2 field of
* %MC_CMD_GET_CAPABILITIES response)
* @rx_dpcpu_fw_id: Firmware ID of the RxDPCPU * @rx_dpcpu_fw_id: Firmware ID of the RxDPCPU
* @tx_dpcpu_fw_id: Firmware ID of the TxDPCPU * @tx_dpcpu_fw_id: Firmware ID of the TxDPCPU
* @vport_id: The function's vport ID, only relevant for PFs * @vport_id: The function's vport ID, only relevant for PFs
...@@ -540,8 +543,10 @@ struct efx_ef10_nic_data { ...@@ -540,8 +543,10 @@ struct efx_ef10_nic_data {
u64 stats[EF10_STAT_COUNT]; u64 stats[EF10_STAT_COUNT];
bool workaround_35388; bool workaround_35388;
bool workaround_26807; bool workaround_26807;
bool workaround_61265;
bool must_check_datapath_caps; bool must_check_datapath_caps;
u32 datapath_caps; u32 datapath_caps;
u32 datapath_caps2;
unsigned int rx_dpcpu_fw_id; unsigned int rx_dpcpu_fw_id;
unsigned int tx_dpcpu_fw_id; unsigned int tx_dpcpu_fw_id;
unsigned int vport_id; unsigned int vport_id;
......
...@@ -1306,7 +1306,7 @@ static int efx_ptp_probe_channel(struct efx_channel *channel) ...@@ -1306,7 +1306,7 @@ static int efx_ptp_probe_channel(struct efx_channel *channel)
{ {
struct efx_nic *efx = channel->efx; struct efx_nic *efx = channel->efx;
channel->irq_moderation = 0; channel->irq_moderation_us = 0;
channel->rx_queue.core_index = 0; channel->rx_queue.core_index = 0;
return efx_ptp_probe(efx, channel); return efx_ptp_probe(efx, channel);
......
...@@ -34,19 +34,24 @@ static void siena_init_wol(struct efx_nic *efx); ...@@ -34,19 +34,24 @@ static void siena_init_wol(struct efx_nic *efx);
static void siena_push_irq_moderation(struct efx_channel *channel) static void siena_push_irq_moderation(struct efx_channel *channel)
{ {
struct efx_nic *efx = channel->efx;
efx_dword_t timer_cmd; efx_dword_t timer_cmd;
if (channel->irq_moderation) if (channel->irq_moderation_us) {
unsigned int ticks;
ticks = efx_usecs_to_ticks(efx, channel->irq_moderation_us);
EFX_POPULATE_DWORD_2(timer_cmd, EFX_POPULATE_DWORD_2(timer_cmd,
FRF_CZ_TC_TIMER_MODE, FRF_CZ_TC_TIMER_MODE,
FFE_CZ_TIMER_MODE_INT_HLDOFF, FFE_CZ_TIMER_MODE_INT_HLDOFF,
FRF_CZ_TC_TIMER_VAL, FRF_CZ_TC_TIMER_VAL,
channel->irq_moderation - 1); ticks - 1);
else } else {
EFX_POPULATE_DWORD_2(timer_cmd, EFX_POPULATE_DWORD_2(timer_cmd,
FRF_CZ_TC_TIMER_MODE, FRF_CZ_TC_TIMER_MODE,
FFE_CZ_TIMER_MODE_DIS, FFE_CZ_TIMER_MODE_DIS,
FRF_CZ_TC_TIMER_VAL, 0); FRF_CZ_TC_TIMER_VAL, 0);
}
efx_writed_page_locked(channel->efx, &timer_cmd, FR_BZ_TIMER_COMMAND_P0, efx_writed_page_locked(channel->efx, &timer_cmd, FR_BZ_TIMER_COMMAND_P0,
channel->channel); channel->channel);
} }
...@@ -222,6 +227,9 @@ static int siena_probe_nvconfig(struct efx_nic *efx) ...@@ -222,6 +227,9 @@ static int siena_probe_nvconfig(struct efx_nic *efx)
efx->timer_quantum_ns = efx->timer_quantum_ns =
(caps & (1 << MC_CMD_CAPABILITIES_TURBO_ACTIVE_LBN)) ? (caps & (1 << MC_CMD_CAPABILITIES_TURBO_ACTIVE_LBN)) ?
3072 : 6144; /* 768 cycles */ 3072 : 6144; /* 768 cycles */
efx->timer_max_ns = efx->type->timer_period_max *
efx->timer_quantum_ns;
return rc; return rc;
} }
......
...@@ -50,4 +50,8 @@ ...@@ -50,4 +50,8 @@
#define EFX_WORKAROUND_35388(efx) \ #define EFX_WORKAROUND_35388(efx) \
(efx_nic_rev(efx) == EFX_REV_HUNT_A0 && EFX_EF10_WORKAROUND_35388(efx)) (efx_nic_rev(efx) == EFX_REV_HUNT_A0 && EFX_EF10_WORKAROUND_35388(efx))
/* Moderation timer access must go through MCDI */
#define EFX_EF10_WORKAROUND_61265(efx) \
(((struct efx_ef10_nic_data *)efx->nic_data)->workaround_61265)
#endif /* EFX_WORKAROUNDS_H */ #endif /* EFX_WORKAROUNDS_H */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment