-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Just a handful of function, but also removed many 'static' identifiers so the code builds. These will, of course, be moved. Module parameters for IRQ moderation threshold also moved. Small code styling fixes included. Signed-off-by: Alexandru-Mihai Maftei <amaftei@solarflare.com> Signed-off-by: David S. Miller <davem@davemloft.net>
- Loading branch information
Alex Maftei (amaftei)
authored and
David S. Miller
committed
Jan 8, 2020
1 parent
f182675
commit 768fd26
Showing
3 changed files
with
190 additions
and
170 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,189 @@ | ||
// SPDX-License-Identifier: GPL-2.0-only | ||
/**************************************************************************** | ||
* Driver for Solarflare network controllers and boards | ||
* Copyright 2018 Solarflare Communications Inc. | ||
* | ||
* This program is free software; you can redistribute it and/or modify it | ||
* under the terms of the GNU General Public License version 2 as published | ||
* by the Free Software Foundation, incorporated herein by reference. | ||
*/ | ||
|
||
#include "net_driver.h" | ||
#include <linux/module.h> | ||
#include "efx_channels.h" | ||
#include "efx.h" | ||
#include "efx_common.h" | ||
#include "tx_common.h" | ||
#include "rx_common.h" | ||
#include "nic.h" | ||
#include "sriov.h" | ||
|
||
static unsigned int irq_adapt_low_thresh = 8000; | ||
module_param(irq_adapt_low_thresh, uint, 0644); | ||
MODULE_PARM_DESC(irq_adapt_low_thresh, | ||
"Threshold score for reducing IRQ moderation"); | ||
|
||
static unsigned int irq_adapt_high_thresh = 16000; | ||
module_param(irq_adapt_high_thresh, uint, 0644); | ||
MODULE_PARM_DESC(irq_adapt_high_thresh, | ||
"Threshold score for increasing IRQ moderation"); | ||
|
||
/* This is the weight assigned to each of the (per-channel) virtual | ||
* NAPI devices. | ||
*/ | ||
static int napi_weight = 64; | ||
|
||
/************************************************************************** | ||
* | ||
* NAPI interface | ||
* | ||
*************************************************************************/ | ||
|
||
/* Process channel's event queue | ||
* | ||
* This function is responsible for processing the event queue of a | ||
* single channel. The caller must guarantee that this function will | ||
* never be concurrently called more than once on the same channel, | ||
* though different channels may be being processed concurrently. | ||
*/ | ||
static int efx_process_channel(struct efx_channel *channel, int budget) | ||
{ | ||
struct efx_tx_queue *tx_queue; | ||
struct list_head rx_list; | ||
int spent; | ||
|
||
if (unlikely(!channel->enabled)) | ||
return 0; | ||
|
||
/* Prepare the batch receive list */ | ||
EFX_WARN_ON_PARANOID(channel->rx_list != NULL); | ||
INIT_LIST_HEAD(&rx_list); | ||
channel->rx_list = &rx_list; | ||
|
||
efx_for_each_channel_tx_queue(tx_queue, channel) { | ||
tx_queue->pkts_compl = 0; | ||
tx_queue->bytes_compl = 0; | ||
} | ||
|
||
spent = efx_nic_process_eventq(channel, budget); | ||
if (spent && efx_channel_has_rx_queue(channel)) { | ||
struct efx_rx_queue *rx_queue = | ||
efx_channel_get_rx_queue(channel); | ||
|
||
efx_rx_flush_packet(channel); | ||
efx_fast_push_rx_descriptors(rx_queue, true); | ||
} | ||
|
||
/* Update BQL */ | ||
efx_for_each_channel_tx_queue(tx_queue, channel) { | ||
if (tx_queue->bytes_compl) { | ||
netdev_tx_completed_queue(tx_queue->core_txq, | ||
tx_queue->pkts_compl, | ||
tx_queue->bytes_compl); | ||
} | ||
} | ||
|
||
/* Receive any packets we queued up */ | ||
netif_receive_skb_list(channel->rx_list); | ||
channel->rx_list = NULL; | ||
|
||
return spent; | ||
} | ||
|
||
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; | ||
} | ||
|
||
/* NAPI poll handler | ||
* | ||
* NAPI guarantees serialisation of polls of the same device, which | ||
* provides the guarantee required by efx_process_channel(). | ||
*/ | ||
static int efx_poll(struct napi_struct *napi, int budget) | ||
{ | ||
struct efx_channel *channel = | ||
container_of(napi, struct efx_channel, napi_str); | ||
struct efx_nic *efx = channel->efx; | ||
int spent; | ||
|
||
netif_vdbg(efx, intr, efx->net_dev, | ||
"channel %d NAPI poll executing on CPU %d\n", | ||
channel->channel, raw_smp_processor_id()); | ||
|
||
spent = efx_process_channel(channel, budget); | ||
|
||
xdp_do_flush_map(); | ||
|
||
if (spent < budget) { | ||
if (efx_channel_has_rx_queue(channel) && | ||
efx->irq_rx_adaptive && | ||
unlikely(++channel->irq_count == 1000)) { | ||
efx_update_irq_mod(efx, channel); | ||
} | ||
|
||
#ifdef CONFIG_RFS_ACCEL | ||
/* Perhaps expire some ARFS filters */ | ||
mod_delayed_work(system_wq, &channel->filter_work, 0); | ||
#endif | ||
|
||
/* There is no race here; although napi_disable() will | ||
* only wait for napi_complete(), this isn't a problem | ||
* since efx_nic_eventq_read_ack() will have no effect if | ||
* interrupts have already been disabled. | ||
*/ | ||
if (napi_complete_done(napi, spent)) | ||
efx_nic_eventq_read_ack(channel); | ||
} | ||
|
||
return spent; | ||
} | ||
|
||
void efx_init_napi_channel(struct efx_channel *channel) | ||
{ | ||
struct efx_nic *efx = channel->efx; | ||
|
||
channel->napi_dev = efx->net_dev; | ||
netif_napi_add(channel->napi_dev, &channel->napi_str, | ||
efx_poll, napi_weight); | ||
} | ||
|
||
void efx_init_napi(struct efx_nic *efx) | ||
{ | ||
struct efx_channel *channel; | ||
|
||
efx_for_each_channel(channel, efx) | ||
efx_init_napi_channel(channel); | ||
} | ||
|
||
void efx_fini_napi_channel(struct efx_channel *channel) | ||
{ | ||
if (channel->napi_dev) | ||
netif_napi_del(&channel->napi_str); | ||
|
||
channel->napi_dev = NULL; | ||
} | ||
|
||
void efx_fini_napi(struct efx_nic *efx) | ||
{ | ||
struct efx_channel *channel; | ||
|
||
efx_for_each_channel(channel, efx) | ||
efx_fini_napi_channel(channel); | ||
} |