Commit d5df7c41 authored by David S. Miller's avatar David S. Miller
parents 80703d26 cd2d5b52
......@@ -26,3 +26,11 @@ config SFC_MCDI_MON
----help---
This exposes the on-board firmware-managed sensors as a
hardware monitor device.
config SFC_SRIOV
bool "Solarflare SFC9000-family SR-IOV support"
depends on SFC && PCI_IOV
default y
---help---
This enables support for the SFC9000 I/O Virtualization
features, allowing accelerated network performance in
virtualized environments.
......@@ -4,5 +4,6 @@ sfc-y += efx.o nic.o falcon.o siena.o tx.o rx.o filter.o \
tenxpress.o txc43128_phy.o falcon_boards.o \
mcdi.o mcdi_phy.o mcdi_mon.o
sfc-$(CONFIG_SFC_MTD) += mtd.o
sfc-$(CONFIG_SFC_SRIOV) += siena_sriov.o
obj-$(CONFIG_SFC) += sfc.o
......@@ -186,9 +186,13 @@ MODULE_PARM_DESC(debug, "Bitmapped debugging message enable value");
*
*************************************************************************/
static void efx_start_interrupts(struct efx_nic *efx, bool may_keep_eventq);
static void efx_stop_interrupts(struct efx_nic *efx, bool may_keep_eventq);
static void efx_remove_channel(struct efx_channel *channel);
static void efx_remove_channels(struct efx_nic *efx);
static const struct efx_channel_type efx_default_channel_type;
static void efx_remove_port(struct efx_nic *efx);
static void efx_init_napi(struct efx_nic *efx);
static void efx_init_napi_channel(struct efx_channel *channel);
static void efx_fini_napi(struct efx_nic *efx);
static void efx_fini_napi_channel(struct efx_channel *channel);
static void efx_fini_struct(struct efx_nic *efx);
......@@ -217,26 +221,27 @@ static void efx_stop_all(struct efx_nic *efx);
*/
static int efx_process_channel(struct efx_channel *channel, int budget)
{
struct efx_nic *efx = channel->efx;
int spent;
if (unlikely(efx->reset_pending || !channel->enabled))
if (unlikely(!channel->enabled))
return 0;
spent = efx_nic_process_eventq(channel, budget);
if (spent == 0)
return 0;
/* Deliver last RX packet. */
if (channel->rx_pkt) {
__efx_rx_packet(channel, channel->rx_pkt);
channel->rx_pkt = NULL;
if (spent && efx_channel_has_rx_queue(channel)) {
struct efx_rx_queue *rx_queue =
efx_channel_get_rx_queue(channel);
/* Deliver last RX packet. */
if (channel->rx_pkt) {
__efx_rx_packet(channel, channel->rx_pkt);
channel->rx_pkt = NULL;
}
if (rx_queue->enabled) {
efx_rx_strategy(channel);
efx_fast_push_rx_descriptors(rx_queue);
}
}
efx_rx_strategy(channel);
efx_fast_push_rx_descriptors(efx_channel_get_rx_queue(channel));
return spent;
}
......@@ -276,7 +281,7 @@ static int efx_poll(struct napi_struct *napi, int budget)
spent = efx_process_channel(channel, budget);
if (spent < budget) {
if (channel->channel < efx->n_rx_channels &&
if (efx_channel_has_rx_queue(channel) &&
efx->irq_rx_adaptive &&
unlikely(++channel->irq_count == 1000)) {
if (unlikely(channel->irq_mod_score <
......@@ -386,6 +391,34 @@ static void efx_init_eventq(struct efx_channel *channel)
efx_nic_init_eventq(channel);
}
/* Enable event queue processing and NAPI */
static void efx_start_eventq(struct efx_channel *channel)
{
netif_dbg(channel->efx, ifup, channel->efx->net_dev,
"chan %d start event queue\n", channel->channel);
/* The interrupt handler for this channel may set work_pending
* as soon as we enable it. Make sure it's cleared before
* then. Similarly, make sure it sees the enabled flag set.
*/
channel->work_pending = false;
channel->enabled = true;
smp_wmb();
napi_enable(&channel->napi_str);
efx_nic_eventq_read_ack(channel);
}
/* Disable event queue processing and NAPI */
static void efx_stop_eventq(struct efx_channel *channel)
{
if (!channel->enabled)
return;
napi_disable(&channel->napi_str);
channel->enabled = false;
}
static void efx_fini_eventq(struct efx_channel *channel)
{
netif_dbg(channel->efx, drv, channel->efx->net_dev,
......@@ -408,8 +441,7 @@ static void efx_remove_eventq(struct efx_channel *channel)
*
*************************************************************************/
/* Allocate and initialise a channel structure, optionally copying
* parameters (but not resources) from an old channel structure. */
/* Allocate and initialise a channel structure. */
static struct efx_channel *
efx_alloc_channel(struct efx_nic *efx, int i, struct efx_channel *old_channel)
{
......@@ -418,45 +450,60 @@ efx_alloc_channel(struct efx_nic *efx, int i, struct efx_channel *old_channel)
struct efx_tx_queue *tx_queue;
int j;
if (old_channel) {
channel = kmalloc(sizeof(*channel), GFP_KERNEL);
if (!channel)
return NULL;
channel = kzalloc(sizeof(*channel), GFP_KERNEL);
if (!channel)
return NULL;
*channel = *old_channel;
channel->efx = efx;
channel->channel = i;
channel->type = &efx_default_channel_type;
channel->napi_dev = NULL;
memset(&channel->eventq, 0, sizeof(channel->eventq));
for (j = 0; j < EFX_TXQ_TYPES; j++) {
tx_queue = &channel->tx_queue[j];
tx_queue->efx = efx;
tx_queue->queue = i * EFX_TXQ_TYPES + j;
tx_queue->channel = channel;
}
rx_queue = &channel->rx_queue;
rx_queue->buffer = NULL;
memset(&rx_queue->rxd, 0, sizeof(rx_queue->rxd));
rx_queue = &channel->rx_queue;
rx_queue->efx = efx;
setup_timer(&rx_queue->slow_fill, efx_rx_slow_fill,
(unsigned long)rx_queue);
for (j = 0; j < EFX_TXQ_TYPES; j++) {
tx_queue = &channel->tx_queue[j];
if (tx_queue->channel)
tx_queue->channel = channel;
tx_queue->buffer = NULL;
memset(&tx_queue->txd, 0, sizeof(tx_queue->txd));
}
} else {
channel = kzalloc(sizeof(*channel), GFP_KERNEL);
if (!channel)
return NULL;
return channel;
}
channel->efx = efx;
channel->channel = i;
/* Allocate and initialise a channel structure, copying parameters
* (but not resources) from an old channel structure.
*/
static struct efx_channel *
efx_copy_channel(const struct efx_channel *old_channel)
{
struct efx_channel *channel;
struct efx_rx_queue *rx_queue;
struct efx_tx_queue *tx_queue;
int j;
channel = kmalloc(sizeof(*channel), GFP_KERNEL);
if (!channel)
return NULL;
*channel = *old_channel;
channel->napi_dev = NULL;
memset(&channel->eventq, 0, sizeof(channel->eventq));
for (j = 0; j < EFX_TXQ_TYPES; j++) {
tx_queue = &channel->tx_queue[j];
tx_queue->efx = efx;
tx_queue->queue = i * EFX_TXQ_TYPES + j;
for (j = 0; j < EFX_TXQ_TYPES; j++) {
tx_queue = &channel->tx_queue[j];
if (tx_queue->channel)
tx_queue->channel = channel;
}
tx_queue->buffer = NULL;
memset(&tx_queue->txd, 0, sizeof(tx_queue->txd));
}
rx_queue = &channel->rx_queue;
rx_queue->efx = efx;
rx_queue->buffer = NULL;
memset(&rx_queue->rxd, 0, sizeof(rx_queue->rxd));
setup_timer(&rx_queue->slow_fill, efx_rx_slow_fill,
(unsigned long)rx_queue);
......@@ -472,57 +519,62 @@ static int efx_probe_channel(struct efx_channel *channel)
netif_dbg(channel->efx, probe, channel->efx->net_dev,
"creating channel %d\n", channel->channel);
rc = channel->type->pre_probe(channel);
if (rc)
goto fail;
rc = efx_probe_eventq(channel);
if (rc)
goto fail1;
goto fail;
efx_for_each_channel_tx_queue(tx_queue, channel) {
rc = efx_probe_tx_queue(tx_queue);
if (rc)
goto fail2;
goto fail;
}
efx_for_each_channel_rx_queue(rx_queue, channel) {
rc = efx_probe_rx_queue(rx_queue);
if (rc)
goto fail3;
goto fail;
}
channel->n_rx_frm_trunc = 0;
return 0;
fail3:
efx_for_each_channel_rx_queue(rx_queue, channel)
efx_remove_rx_queue(rx_queue);
fail2:
efx_for_each_channel_tx_queue(tx_queue, channel)
efx_remove_tx_queue(tx_queue);
fail1:
fail:
efx_remove_channel(channel);
return rc;
}
static void
efx_get_channel_name(struct efx_channel *channel, char *buf, size_t len)
{
struct efx_nic *efx = channel->efx;
const char *type;
int number;
number = channel->channel;
if (efx->tx_channel_offset == 0) {
type = "";
} else if (channel->channel < efx->tx_channel_offset) {
type = "-rx";
} else {
type = "-tx";
number -= efx->tx_channel_offset;
}
snprintf(buf, len, "%s%s-%d", efx->name, type, number);
}
static void efx_set_channel_names(struct efx_nic *efx)
{
struct efx_channel *channel;
const char *type = "";
int number;
efx_for_each_channel(channel, efx) {
number = channel->channel;
if (efx->n_channels > efx->n_rx_channels) {
if (channel->channel < efx->n_rx_channels) {
type = "-rx";
} else {
type = "-tx";
number -= efx->n_rx_channels;
}
}
snprintf(efx->channel_name[channel->channel],
sizeof(efx->channel_name[0]),
"%s%s-%d", efx->name, type, number);
}
efx_for_each_channel(channel, efx)
channel->type->get_name(channel,
efx->channel_name[channel->channel],
sizeof(efx->channel_name[0]));
}
static int efx_probe_channels(struct efx_nic *efx)
......@@ -555,7 +607,7 @@ static int efx_probe_channels(struct efx_nic *efx)
* to propagate configuration changes (mtu, checksum offload), or
* to clear hardware error conditions
*/
static void efx_init_channels(struct efx_nic *efx)
static void efx_start_datapath(struct efx_nic *efx)
{
struct efx_tx_queue *tx_queue;
struct efx_rx_queue *rx_queue;
......@@ -574,68 +626,26 @@ static void efx_init_channels(struct efx_nic *efx)
/* Initialise the channels */
efx_for_each_channel(channel, efx) {
netif_dbg(channel->efx, drv, channel->efx->net_dev,
"init chan %d\n", channel->channel);
efx_init_eventq(channel);
efx_for_each_channel_tx_queue(tx_queue, channel)
efx_init_tx_queue(tx_queue);
/* The rx buffer allocation strategy is MTU dependent */
efx_rx_strategy(channel);
efx_for_each_channel_rx_queue(rx_queue, channel)
efx_for_each_channel_rx_queue(rx_queue, channel) {
efx_init_rx_queue(rx_queue);
efx_nic_generate_fill_event(rx_queue);
}
WARN_ON(channel->rx_pkt != NULL);
efx_rx_strategy(channel);
}
}
/* This enables event queue processing and packet transmission.
*
* Note that this function is not allowed to fail, since that would
* introduce too much complexity into the suspend/resume path.
*/
static void efx_start_channel(struct efx_channel *channel)
{
struct efx_rx_queue *rx_queue;
netif_dbg(channel->efx, ifup, channel->efx->net_dev,
"starting chan %d\n", channel->channel);
/* The interrupt handler for this channel may set work_pending
* as soon as we enable it. Make sure it's cleared before
* then. Similarly, make sure it sees the enabled flag set. */
channel->work_pending = false;
channel->enabled = true;
smp_wmb();
/* Fill the queues before enabling NAPI */
efx_for_each_channel_rx_queue(rx_queue, channel)
efx_fast_push_rx_descriptors(rx_queue);
napi_enable(&channel->napi_str);
}
/* This disables event queue processing and packet transmission.
* This function does not guarantee that all queue processing
* (e.g. RX refill) is complete.
*/
static void efx_stop_channel(struct efx_channel *channel)
{
if (!channel->enabled)
return;
netif_dbg(channel->efx, ifdown, channel->efx->net_dev,
"stop chan %d\n", channel->channel);
channel->enabled = false;
napi_disable(&channel->napi_str);
if (netif_device_present(efx->net_dev))
netif_tx_wake_all_queues(efx->net_dev);
}
static void efx_fini_channels(struct efx_nic *efx)
static void efx_stop_datapath(struct efx_nic *efx)
{
struct efx_channel *channel;
struct efx_tx_queue *tx_queue;
......@@ -662,14 +672,21 @@ static void efx_fini_channels(struct efx_nic *efx)
}
efx_for_each_channel(channel, efx) {
netif_dbg(channel->efx, drv, channel->efx->net_dev,
"shut down chan %d\n", channel->channel);
/* RX packet processing is pipelined, so wait for the
* NAPI handler to complete. At least event queue 0
* might be kept active by non-data events, so don't
* use napi_synchronize() but actually disable NAPI
* temporarily.
*/
if (efx_channel_has_rx_queue(channel)) {
efx_stop_eventq(channel);
efx_start_eventq(channel);
}
efx_for_each_channel_rx_queue(rx_queue, channel)
efx_fini_rx_queue(rx_queue);
efx_for_each_possible_channel_tx_queue(tx_queue, channel)
efx_fini_tx_queue(tx_queue);
efx_fini_eventq(channel);
}
}
......@@ -701,16 +718,40 @@ efx_realloc_channels(struct efx_nic *efx, u32 rxq_entries, u32 txq_entries)
{
struct efx_channel *other_channel[EFX_MAX_CHANNELS], *channel;
u32 old_rxq_entries, old_txq_entries;
unsigned i;
int rc;
unsigned i, next_buffer_table = 0;
int rc = 0;
/* Not all channels should be reallocated. We must avoid
* reallocating their buffer table entries.
*/
efx_for_each_channel(channel, efx) {
struct efx_rx_queue *rx_queue;
struct efx_tx_queue *tx_queue;
if (channel->type->copy)
continue;
next_buffer_table = max(next_buffer_table,
channel->eventq.index +
channel->eventq.entries);
efx_for_each_channel_rx_queue(rx_queue, channel)
next_buffer_table = max(next_buffer_table,
rx_queue->rxd.index +
rx_queue->rxd.entries);
efx_for_each_channel_tx_queue(tx_queue, channel)
next_buffer_table = max(next_buffer_table,
tx_queue->txd.index +
tx_queue->txd.entries);
}
efx_stop_all(efx);
efx_fini_channels(efx);
efx_stop_interrupts(efx, true);
/* Clone channels */
/* Clone channels (where possible) */
memset(other_channel, 0, sizeof(other_channel));
for (i = 0; i < efx->n_channels; i++) {
channel = efx_alloc_channel(efx, i, efx->channel[i]);
channel = efx->channel[i];
if (channel->type->copy)
channel = channel->type->copy(channel);
if (!channel) {
rc = -ENOMEM;
goto out;
......@@ -729,23 +770,31 @@ efx_realloc_channels(struct efx_nic *efx, u32 rxq_entries, u32 txq_entries)
other_channel[i] = channel;
}
rc = efx_probe_channels(efx);
if (rc)
goto rollback;
efx_init_napi(efx);
/* Restart buffer table allocation */
efx->next_buffer_table = next_buffer_table;
/* Destroy old channels */
for (i = 0; i < efx->n_channels; i++) {
efx_fini_napi_channel(other_channel[i]);
efx_remove_channel(other_channel[i]);
channel = efx->channel[i];
if (!channel->type->copy)
continue;
rc = efx_probe_channel(channel);
if (rc)
goto rollback;
efx_init_napi_channel(efx->channel[i]);
}
out:
/* Free unused channel structures */
for (i = 0; i < efx->n_channels; i++)
kfree(other_channel[i]);
/* Destroy unused channel structures */
for (i = 0; i < efx->n_channels; i++) {
channel = other_channel[i];
if (channel && channel->type->copy) {
efx_fini_napi_channel(channel);
efx_remove_channel(channel);
kfree(channel);
}
}
efx_init_channels(efx);
efx_start_interrupts(efx, true);
efx_start_all(efx);
return rc;
......@@ -766,6 +815,18 @@ void efx_schedule_slow_fill(struct efx_rx_queue *rx_queue)
mod_timer(&rx_queue->slow_fill, jiffies + msecs_to_jiffies(100));
}
static const struct efx_channel_type efx_default_channel_type = {
.pre_probe = efx_channel_dummy_op_int,
.get_name = efx_get_channel_name,
.copy = efx_copy_channel,
.keep_eventq = false,
};
int efx_channel_dummy_op_int(struct efx_channel *channel)
{
return 0;
}
/**************************************************************************
*
* Port handling
......@@ -1108,31 +1169,46 @@ static void efx_fini_io(struct efx_nic *efx)
pci_disable_device(efx->pci_dev);
}
static int efx_wanted_parallelism(void)
static unsigned int efx_wanted_parallelism(struct efx_nic *efx)
{
cpumask_var_t thread_mask;
int count;
unsigned int count;
int cpu;
if (rss_cpus)
return rss_cpus;
if (rss_cpus) {
count = rss_cpus;
} else {
if (unlikely(!zalloc_cpumask_var(&thread_mask, GFP_KERNEL))) {
netif_warn(efx, probe, efx->net_dev,
"RSS disabled due to allocation failure\n");
return 1;
}
count = 0;
for_each_online_cpu(cpu) {
if (!cpumask_test_cpu(cpu, thread_mask)) {
++count;
cpumask_or(thread_mask, thread_mask,
topology_thread_cpumask(cpu));
}
}
if (unlikely(!zalloc_cpumask_var(&thread_mask, GFP_KERNEL))) {
printk(KERN_WARNING
"sfc: RSS disabled due to allocation failure\n");
return 1;
free_cpumask_var(thread_mask);
}
count = 0;
for_each_online_cpu(cpu) {
if (!cpumask_test_cpu(cpu, thread_mask)) {
++count;
cpumask_or(thread_mask, thread_mask,
topology_thread_cpumask(cpu));
}
/* If RSS is requested for the PF *and* VFs then we can't write RSS
* table entries that are inaccessible to VFs
*/
if (efx_sriov_wanted(efx) && efx_vf_size(efx) > 1 &&
count > efx_vf_size(efx)) {
netif_warn(efx, probe, efx->net_dev,
"Reducing number of RSS channels from %u to %u for "
"VF support. Increase vf-msix-limit to use more "
"channels on the PF.\n",
count, efx_vf_size(efx));
count = efx_vf_size(efx);
}
free_cpumask_var(thread_mask);
return count;
}
......@@ -1140,7 +1216,8 @@ static int
efx_init_rx_cpu_rmap(struct efx_nic *efx, struct msix_entry *xentries)
{
#ifdef CONFIG_RFS_ACCEL
int i, rc;
unsigned int i;
int rc;
efx->net_dev->rx_cpu_rmap = alloc_irq_cpu_rmap(efx->n_rx_channels);
if (!efx->net_dev->rx_cpu_rmap)
......@@ -1163,17 +1240,24 @@ efx_init_rx_cpu_rmap(struct efx_nic *efx, struct msix_entry *xentries)
*/
static int efx_probe_interrupts(struct efx_nic *efx)
{
int max_channels =
min_t(int, efx->type->phys_addr_channels, EFX_MAX_CHANNELS);
int rc, i;
unsigned int max_channels =
min(efx->type->phys_addr_channels, EFX_MAX_CHANNELS);
unsigned int extra_channels = 0;
unsigned int i, j;
int rc;
for (i = 0; i < EFX_MAX_EXTRA_CHANNELS; i++)
if (efx->extra_channel_type[i])
++extra_channels;
if (efx->interrupt_mode == EFX_INT_MODE_MSIX) {
struct msix_entry xentries[EFX_MAX_CHANNELS];
int n_channels;
unsigned int n_channels;
n_channels = efx_wanted_parallelism();
n_channels = efx_wanted_parallelism(efx);
if (separate_tx_channels)
n_channels *= 2;
n_channels += extra_channels;
n_channels = min(n_channels, max_channels);
for (i = 0; i < n_channels; i++)
......@@ -1182,7 +1266,7 @@ static int efx_probe_interrupts(struct efx_nic *efx)
if (rc > 0) {
netif_err(efx, drv, efx->net_dev,
"WARNING: Insufficient MSI-X vectors"
" available (%d < %d).\n", rc, n_channels);
" available (%d < %u).\n", rc, n_channels);
netif_err(efx, drv, efx->net_dev,
"WARNING: Performance may be reduced.\n");
EFX_BUG_ON_PARANOID(rc >= n_channels);
......@@ -1193,22 +1277,23 @@ static int efx_probe_interrupts(struct efx_nic *efx)
if (rc == 0) {
efx->n_channels = n_channels;
if (n_channels > extra_channels)
n_channels -= extra_channels;
if (separate_tx_channels) {
efx->n_tx_channels =
max(efx->n_channels / 2, 1U);
efx->n_rx_channels =
max(efx->n_channels -
efx->n_tx_channels, 1U);
efx->n_tx_channels = max(n_channels / 2, 1U);
efx->n_rx_channels = max(n_channels -
efx->n_tx_channels,
1U);
} else {
efx->n_tx_channels = efx->n_channels;
efx->n_rx_channels = efx->n_channels;
efx->n_tx_channels = n_channels;
efx->n_rx_channels = n_channels;
}
rc = efx_init_rx_cpu_rmap(efx, xentries);
if (rc) {
pci_disable_msix(efx->pci_dev);
return rc;
}
for (i = 0; i < n_channels; i++)
for (i = 0; i < efx->n_channels; i++)
efx_get_channel(efx, i)->irq =
xentries[i].vector;
} else {
......@@ -1242,9 +1327,68 @@ static int efx_probe_interrupts(struct efx_nic *efx)
efx->legacy_irq = efx->pci_dev->irq;
}
/* Assign extra channels if possible */
j = efx->n_channels;
for (i = 0; i < EFX_MAX_EXTRA_CHANNELS; i++) {
if (!efx->extra_channel_type[i])
continue;
if (efx->interrupt_mode != EFX_INT_MODE_MSIX ||
efx->n_channels <= extra_channels) {
efx->extra_channel_type[i]->handle_no_channel(efx);
} else {
--j;
efx_get_channel(efx, j)->type =
efx->extra_channel_type[i];
}
}
/* RSS might be usable on VFs even if it is disabled on the PF */
efx->rss_spread = (efx->n_rx_channels > 1 ?
efx->n_rx_channels : efx_vf_size(efx));
return 0;
}
/* Enable interrupts, then probe and start the event queues */
static void efx_start_interrupts(struct efx_nic *efx, bool may_keep_eventq)
{
struct efx_channel *channel;
if (efx->legacy_irq)
efx->legacy_irq_enabled = true;
efx_nic_enable_interrupts(efx);
efx_for_each_channel(channel, efx) {
if (!channel->type->keep_eventq || !may_keep_eventq)
efx_init_eventq(channel);
efx_start_eventq(channel);
}
efx_mcdi_mode_event(efx);
}
static void efx_stop_interrupts(struct efx_nic *efx, bool may_keep_eventq)
{
struct efx_channel *channel;
efx_mcdi_mode_poll(efx);
efx_nic_disable_interrupts(efx);
if (efx->legacy_irq) {
synchronize_irq(efx->legacy_irq);
efx->legacy_irq_enabled = false;
}
efx_for_each_channel(channel, efx) {
if (channel->irq)
synchronize_irq(channel->irq);
efx_stop_eventq(channel);
if (!channel->type->keep_eventq || !may_keep_eventq)
efx_fini_eventq(channel);
}
}
static void efx_remove_interrupts(struct efx_nic *efx)
{
struct efx_channel *channel;
......@@ -1295,11 +1439,13 @@ static int efx_probe_nic(struct efx_nic *efx)
if (rc)
goto fail;
efx->type->dimension_resources(efx);
if (efx->n_channels > 1)
get_random_bytes(&efx->rx_hash_key, sizeof(efx->rx_hash_key));
for (i = 0; i < ARRAY_SIZE(efx->rx_indir_table); i++)
efx->rx_indir_table[i] =
ethtool_rxfh_indir_default(i, efx->n_rx_channels);
ethtool_rxfh_indir_default(i, efx->rss_spread);
efx_set_channels(efx);
netif_set_real_num_tx_queues(efx->net_dev, efx->n_tx_channels);
......@@ -1347,21 +1493,22 @@ static int efx_probe_all(struct efx_nic *efx)
}
efx->rxq_entries = efx->txq_entries = EFX_DEFAULT_DMAQ_SIZE;
rc = efx_probe_channels(efx);
if (rc)
goto fail3;
rc = efx_probe_filters(efx);
if (rc) {
netif_err(efx, probe, efx->net_dev,
"failed to create filter tables\n");
goto fail4;
goto fail3;
}
rc = efx_probe_channels(efx);
if (rc)
goto fail4;
return 0;
fail4:
efx_remove_channels(efx);
efx_remove_filters(efx);
fail3:
efx_remove_port(efx);
fail2:
......@@ -1370,15 +1517,13 @@ static int efx_probe_all(struct efx_nic *efx)
return rc;
}
/* Called after previous invocation(s) of efx_stop_all, restarts the
* port, kernel transmit queue, NAPI processing and hardware interrupts,
* and ensures that the port is scheduled to be reconfigured.
* This function is safe to call multiple times when the NIC is in any
* state. */
/* Called after previous invocation(s) of efx_stop_all, restarts the port,
* kernel transmit queues and NAPI processing, and ensures that the port is
* scheduled to be reconfigured. This function is safe to call multiple
* times when the NIC is in any state.
*/
static void efx_start_all(struct efx_nic *efx)
{
struct efx_channel *channel;
EFX_ASSERT_RESET_SERIALISED(efx);
/* Check that it is appropriate to restart the interface. All
......@@ -1390,28 +1535,8 @@ static void efx_start_all(struct efx_nic *efx)
if (!netif_running(efx->net_dev))
return;
/* Mark the port as enabled so port reconfigurations can start, then
* restart the transmit interface early so the watchdog timer stops */
efx_start_port(efx);
if (netif_device_present(efx->net_dev))
netif_tx_wake_all_queues(efx->net_dev);
efx_for_each_channel(channel, efx)
efx_start_channel(channel);
if (efx->legacy_irq)
efx->legacy_irq_enabled = true;
efx_nic_enable_interrupts(efx);
/* Switch to event based MCDI completions after enabling interrupts.
* If a reset has been scheduled, then we need to stay in polled mode.
* Rather than serialising efx_mcdi_mode_event() [which sleeps] and
* reset_pending [modified from an atomic context], we instead guarantee
* that efx_mcdi_mode_poll() isn't reverted erroneously */
efx_mcdi_mode_event(efx);
if (efx->reset_pending)
efx_mcdi_mode_poll(efx);
efx_start_datapath(efx);
/* Start the hardware monitor if there is one. Otherwise (we're link
* event driven), we have to poll the PHY because after an event queue
......@@ -1447,8 +1572,6 @@ static void efx_flush_all(struct efx_nic *efx)
* taking locks. */
static void efx_stop_all(struct efx_nic *efx)
{
struct efx_channel *channel;
EFX_ASSERT_RESET_SERIALISED(efx);
/* port_enabled can be read safely under the rtnl lock */
......@@ -1456,28 +1579,6 @@ static void efx_stop_all(struct efx_nic *efx)
return;
efx->type->stop_stats(efx);
/* Switch to MCDI polling on Siena before disabling interrupts */
efx_mcdi_mode_poll(efx);
/* Disable interrupts and wait for ISR to complete */
efx_nic_disable_interrupts(efx);
if (efx->legacy_irq) {
synchronize_irq(efx->legacy_irq);
efx->legacy_irq_enabled = false;
}
efx_for_each_channel(channel, efx) {
if (channel->irq)
synchronize_irq(channel->irq);
}
/* Stop all NAPI processing and synchronous rx refills */
efx_for_each_channel(channel, efx)
efx_stop_channel(channel);
/* Stop all asynchronous port reconfigurations. Since all
* event processing has already been stopped, there is no
* window to loose phy events */
efx_stop_port(efx);
/* Flush efx_mac_work(), refill_workqueue, monitor_work */
......@@ -1485,15 +1586,15 @@ static void efx_stop_all(struct efx_nic *efx)
/* Stop the kernel transmit interface late, so the watchdog
* timer isn't ticking over the flush */
netif_tx_stop_all_queues(efx->net_dev);
netif_tx_lock_bh(efx->net_dev);
netif_tx_unlock_bh(efx->net_dev);
netif_tx_disable(efx->net_dev);
efx_stop_datapath(efx);
}
static void efx_remove_all(struct efx_nic *efx)
{
efx_remove_filters(efx);
efx_remove_channels(efx);
efx_remove_filters(efx);
efx_remove_port(efx);
efx_remove_nic(efx);
}
......@@ -1637,15 +1738,21 @@ static int efx_ioctl(struct net_device *net_dev, struct ifreq *ifr, int cmd)
*
**************************************************************************/
static 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);
}
static void efx_init_napi(struct efx_nic *efx)
{
struct efx_channel *channel;
efx_for_each_channel(channel, efx) {
channel->napi_dev = efx->net_dev;
netif_napi_add(channel->napi_dev, &channel->napi_str,
efx_poll, napi_weight);
}
efx_for_each_channel(channel, efx)
efx_init_napi_channel(channel);
}
static void efx_fini_napi_channel(struct efx_channel *channel)
......@@ -1730,8 +1837,6 @@ static int efx_net_stop(struct net_device *net_dev)
if (efx->state != STATE_DISABLED) {
/* Stop the device and flush all the channels */
efx_stop_all(efx);
efx_fini_channels(efx);
efx_init_channels(efx);
}
return 0;
......@@ -1802,8 +1907,6 @@ static int efx_change_mtu(struct net_device *net_dev, int new_mtu)
netif_dbg(efx, drv, efx->net_dev, "changing MTU to %d\n", new_mtu);
efx_fini_channels(efx);
mutex_lock(&efx->mac_lock);
/* Reconfigure the MAC before enabling the dma queues so that
* the RX buffers don't overflow */
......@@ -1811,8 +1914,6 @@ static int efx_change_mtu(struct net_device *net_dev, int new_mtu)
efx->type->reconfigure_mac(efx);
mutex_unlock(&efx->mac_lock);
efx_init_channels(efx);
efx_start_all(efx);
return 0;
}
......@@ -1833,6 +1934,7 @@ static int efx_set_mac_address(struct net_device *net_dev, void *data)
}
memcpy(net_dev->dev_addr, new_addr, net_dev->addr_len);
efx_sriov_mac_address_changed(efx);
/* Reconfigure the MAC */
mutex_lock(&efx->mac_lock);
......@@ -1899,6 +2001,12 @@ static const struct net_device_ops efx_netdev_ops = {
.ndo_set_mac_address = efx_set_mac_address,
.ndo_set_rx_mode = efx_set_rx_mode,
.ndo_set_features = efx_set_features,
#ifdef CONFIG_SFC_SRIOV
.ndo_set_vf_mac = efx_sriov_set_vf_mac,
.ndo_set_vf_vlan = efx_sriov_set_vf_vlan,
.ndo_set_vf_spoofchk = efx_sriov_set_vf_spoofchk,
.ndo_get_vf_config = efx_sriov_get_vf_config,
#endif
#ifdef CONFIG_NET_POLL_CONTROLLER
.ndo_poll_controller = efx_netpoll,
#endif
......@@ -2029,7 +2137,7 @@ void efx_reset_down(struct efx_nic *efx, enum reset_type method)
efx_stop_all(efx);
mutex_lock(&efx->mac_lock);
efx_fini_channels(efx);
efx_stop_interrupts(efx, false);
if (efx->port_initialized && method != RESET_TYPE_INVISIBLE)
efx->phy_op->fini(efx);
efx->type->fini(efx);
......@@ -2066,8 +2174,9 @@ int efx_reset_up(struct efx_nic *efx, enum reset_type method, bool ok)
efx->type->reconfigure_mac(efx);
efx_init_channels(efx);
efx_start_interrupts(efx, false);
efx_restore_filters(efx);
efx_sriov_reset(efx);
mutex_unlock(&efx->mac_lock);
......@@ -2272,6 +2381,7 @@ static int efx_init_struct(struct efx_nic *efx, const struct efx_nic_type *type,
efx->phy_op = &efx_dummy_phy_operations;
efx->mdio.dev = net_dev;
INIT_WORK(&efx->mac_work, efx_mac_work);
init_waitqueue_head(&efx->flush_wq);
for (i = 0; i < EFX_MAX_CHANNELS; i++) {
efx->channel[i] = efx_alloc_channel(efx, i, NULL);
......@@ -2329,8 +2439,8 @@ static void efx_pci_remove_main(struct efx_nic *efx)
free_irq_cpu_rmap(efx->net_dev->rx_cpu_rmap);
efx->net_dev->rx_cpu_rmap = NULL;
#endif
efx_stop_interrupts(efx, false);
efx_nic_fini_interrupt(efx);
efx_fini_channels(efx);
efx_fini_port(efx);
efx->type->fini(efx);
efx_fini_napi(efx);
......@@ -2356,6 +2466,8 @@ static void efx_pci_remove(struct pci_dev *pci_dev)
/* Allow any queued efx_resets() to complete */
rtnl_unlock();
efx_stop_interrupts(efx, false);
efx_sriov_fini(efx);
efx_unregister_netdev(efx);
efx_mtd_remove(efx);
......@@ -2404,16 +2516,14 @@ static int efx_pci_probe_main(struct efx_nic *efx)
goto fail4;
}
efx_init_channels(efx);
rc = efx_nic_init_interrupt(efx);
if (rc)
goto fail5;
efx_start_interrupts(efx, false);
return 0;
fail5:
efx_fini_channels(efx);
efx_fini_port(efx);
fail4:
efx->type->fini(efx);
......@@ -2439,7 +2549,7 @@ static int __devinit efx_pci_probe(struct pci_dev *pci_dev,
const struct efx_nic_type *type = (const struct efx_nic_type *) entry->driver_data;
struct net_device *net_dev;
struct efx_nic *efx;
int i, rc;
int rc;
/* Allocate and initialise a struct net_device and struct efx_nic */
net_dev = alloc_etherdev_mqs(sizeof(*efx), EFX_MAX_CORE_TX_QUEUES,
......@@ -2472,39 +2582,22 @@ static int __devinit efx_pci_probe(struct pci_dev *pci_dev,
if (rc)
goto fail2;
/* No serialisation is required with the reset path because
* we're in STATE_INIT. */
for (i = 0; i < 5; i++) {
rc = efx_pci_probe_main(efx);
rc = efx_pci_probe_main(efx);
/* Serialise against efx_reset(). No more resets will be
* scheduled since efx_stop_all() has been called, and we
* have not and never have been registered with either
* the rtnetlink or driverlink layers. */
cancel_work_sync(&efx->reset_work);
if (rc == 0) {
if (efx->reset_pending) {
/* If there was a scheduled reset during
* probe, the NIC is probably hosed anyway */
efx_pci_remove_main(efx);
rc = -EIO;
} else {
break;
}
}
/* Retry if a recoverably reset event has been scheduled */
if (efx->reset_pending &
~(1 << RESET_TYPE_INVISIBLE | 1 << RESET_TYPE_ALL) ||
!efx->reset_pending)
goto fail3;
/* Serialise against efx_reset(). No more resets will be
* scheduled since efx_stop_all() has been called, and we have
* not and never have been registered.
*/
cancel_work_sync(&efx->reset_work);
efx->reset_pending = 0;
}
if (rc)
goto fail3;
if (rc) {
netif_err(efx, probe, efx->net_dev, "Could not reset NIC\n");
/* If there was a scheduled reset during probe, the NIC is
* probably hosed anyway.
*/
if (efx->reset_pending) {
rc = -EIO;
goto fail4;
}
......@@ -2514,18 +2607,27 @@ static int __devinit efx_pci_probe(struct pci_dev *pci_dev,
rc = efx_register_netdev(efx);
if (rc)
goto fail5;
goto fail4;
rc = efx_sriov_init(efx);
if (rc)
netif_err(efx, probe, efx->net_dev,
"SR-IOV can't be enabled rc %d\n", rc);
netif_dbg(efx, probe, efx->net_dev, "initialisation successful\n");
/* Try to create MTDs, but allow this to fail */
rtnl_lock();
efx_mtd_probe(efx); /* allowed to fail */
rc = efx_mtd_probe(efx);
rtnl_unlock();
if (rc)
netif_warn(efx, probe, efx->net_dev,
"failed to create MTDs (%d)\n", rc);
return 0;
fail5:
efx_pci_remove_main(efx);
fail4:
efx_pci_remove_main(efx);
fail3:
efx_fini_io(efx);
fail2:
......@@ -2546,7 +2648,7 @@ static int efx_pm_freeze(struct device *dev)
netif_device_detach(efx->net_dev);
efx_stop_all(efx);
efx_fini_channels(efx);
efx_stop_interrupts(efx, false);
return 0;
}
......@@ -2557,7 +2659,7 @@ static int efx_pm_thaw(struct device *dev)
efx->state = STATE_INIT;
efx_init_channels(efx);
efx_start_interrupts(efx, false);
mutex_lock(&efx->mac_lock);
efx->phy_op->reconfigure(efx);
......@@ -2663,6 +2765,10 @@ static int __init efx_init_module(void)
if (rc)
goto err_notifier;
rc = efx_init_sriov();
if (rc)
goto err_sriov;
reset_workqueue = create_singlethread_workqueue("sfc_reset");
if (!reset_workqueue) {
rc = -ENOMEM;
......@@ -2678,6 +2784,8 @@ static int __init efx_init_module(void)
err_pci:
destroy_workqueue(reset_workqueue);
err_reset:
efx_fini_sriov();
err_sriov:
unregister_netdevice_notifier(&efx_netdev_notifier);
err_notifier:
return rc;
......@@ -2689,6 +2797,7 @@ static void __exit efx_exit_module(void)
pci_unregister_driver(&efx_pci_driver);
destroy_workqueue(reset_workqueue);
efx_fini_sriov();
unregister_netdevice_notifier(&efx_netdev_notifier);
}
......
......@@ -95,6 +95,7 @@ static inline void efx_filter_rfs_expire(struct efx_channel *channel) {}
#endif
/* Channels */
extern int efx_channel_dummy_op_int(struct efx_channel *channel);
extern void efx_process_channel_now(struct efx_channel *channel);
extern int
efx_realloc_channels(struct efx_nic *efx, u32 rxq_entries, u32 txq_entries);
......
......@@ -808,11 +808,16 @@ static int efx_ethtool_reset(struct net_device *net_dev, u32 *flags)
return efx_reset(efx, rc);
}
/* MAC address mask including only MC flag */
static const u8 mac_addr_mc_mask[ETH_ALEN] = { 0x01, 0, 0, 0, 0, 0 };
static int efx_ethtool_get_class_rule(struct efx_nic *efx,
struct ethtool_rx_flow_spec *rule)
{
struct ethtool_tcpip4_spec *ip_entry = &rule->h_u.tcp_ip4_spec;
struct ethtool_tcpip4_spec *ip_mask = &rule->m_u.tcp_ip4_spec;
struct ethhdr *mac_entry = &rule->h_u.ether_spec;
struct ethhdr *mac_mask = &rule->m_u.ether_spec;
struct efx_filter_spec spec;
u16 vid;
u8 proto;
......@@ -828,11 +833,18 @@ static int efx_ethtool_get_class_rule(struct efx_nic *efx,
else
rule->ring_cookie = spec.dmaq_id;
rc = efx_filter_get_eth_local(&spec, &vid,
rule->h_u.ether_spec.h_dest);
if (spec.type == EFX_FILTER_MC_DEF || spec.type == EFX_FILTER_UC_DEF) {
rule->flow_type = ETHER_FLOW;
memcpy(mac_mask->h_dest, mac_addr_mc_mask, ETH_ALEN);
if (spec.type == EFX_FILTER_MC_DEF)
memcpy(mac_entry->h_dest, mac_addr_mc_mask, ETH_ALEN);
return 0;
}
rc = efx_filter_get_eth_local(&spec, &vid, mac_entry->h_dest);
if (rc == 0) {
rule->flow_type = ETHER_FLOW;
memset(rule->m_u.ether_spec.h_dest, ~0, ETH_ALEN);
memset(mac_mask->h_dest, ~0, ETH_ALEN);
if (vid != EFX_FILTER_VID_UNSPEC) {
rule->flow_type |= FLOW_EXT;
rule->h_ext.vlan_tci = htons(vid);
......@@ -1001,27 +1013,40 @@ static int efx_ethtool_set_class_rule(struct efx_nic *efx,
}
case ETHER_FLOW | FLOW_EXT:
/* Must match all or none of VID */
if (rule->m_ext.vlan_tci != htons(0xfff) &&
rule->m_ext.vlan_tci != 0)
return -EINVAL;
case ETHER_FLOW:
/* Must match all of destination */
if (!is_broadcast_ether_addr(mac_mask->h_dest))
return -EINVAL;
/* and nothing else */
case ETHER_FLOW: {
u16 vlan_tag_mask = (rule->flow_type & FLOW_EXT ?
ntohs(rule->m_ext.vlan_tci) : 0);
/* Must not match on source address or Ethertype */
if (!is_zero_ether_addr(mac_mask->h_source) ||
mac_mask->h_proto)
return -EINVAL;
rc = efx_filter_set_eth_local(
&spec,
(rule->flow_type & FLOW_EXT && rule->m_ext.vlan_tci) ?
ntohs(rule->h_ext.vlan_tci) : EFX_FILTER_VID_UNSPEC,
mac_entry->h_dest);
/* Is it a default UC or MC filter? */
if (!compare_ether_addr(mac_mask->h_dest, mac_addr_mc_mask) &&
vlan_tag_mask == 0) {
if (is_multicast_ether_addr(mac_entry->h_dest))
rc = efx_filter_set_mc_def(&spec);
else
rc = efx_filter_set_uc_def(&spec);
}
/* Otherwise, it must match all of destination and all
* or none of VID.
*/
else if (is_broadcast_ether_addr(mac_mask->h_dest) &&
(vlan_tag_mask == 0xfff || vlan_tag_mask == 0)) {
rc = efx_filter_set_eth_local(
&spec,
vlan_tag_mask ?
ntohs(rule->h_ext.vlan_tci) : EFX_FILTER_VID_UNSPEC,
mac_entry->h_dest);
} else {
rc = -EINVAL;
}
if (rc)
return rc;
break;
}
default:
return -EINVAL;
......@@ -1060,7 +1085,8 @@ static u32 efx_ethtool_get_rxfh_indir_size(struct net_device *net_dev)
{
struct efx_nic *efx = netdev_priv(net_dev);
return (efx_nic_rev(efx) < EFX_REV_FALCON_B0 ?
return ((efx_nic_rev(efx) < EFX_REV_FALCON_B0 ||
efx->n_rx_channels == 1) ?
0 : ARRAY_SIZE(efx->rx_indir_table));
}
......
......@@ -1333,6 +1333,12 @@ static int falcon_probe_nvconfig(struct efx_nic *efx)
return rc;
}
static void falcon_dimension_resources(struct efx_nic *efx)
{
efx->rx_dc_base = 0x20000;
efx->tx_dc_base = 0x26000;
}
/* Probe all SPI devices on the NIC */
static void falcon_probe_spi_devices(struct efx_nic *efx)
{
......@@ -1749,6 +1755,7 @@ const struct efx_nic_type falcon_a1_nic_type = {
.probe = falcon_probe_nic,
.remove = falcon_remove_nic,
.init = falcon_init_nic,
.dimension_resources = falcon_dimension_resources,
.fini = efx_port_dummy_op_void,
.monitor = falcon_monitor,
.map_reset_reason = falcon_map_reset_reason,
......@@ -1783,8 +1790,6 @@ const struct efx_nic_type falcon_a1_nic_type = {
.max_interrupt_mode = EFX_INT_MODE_MSI,
.phys_addr_channels = 4,
.timer_period_max = 1 << FRF_AB_TC_TIMER_VAL_WIDTH,
.tx_dc_base = 0x130000,
.rx_dc_base = 0x100000,
.offload_features = NETIF_F_IP_CSUM,
};
......@@ -1792,6 +1797,7 @@ const struct efx_nic_type falcon_b0_nic_type = {
.probe = falcon_probe_nic,
.remove = falcon_remove_nic,
.init = falcon_init_nic,
.dimension_resources = falcon_dimension_resources,
.fini = efx_port_dummy_op_void,
.monitor = falcon_monitor,
.map_reset_reason = falcon_map_reset_reason,
......@@ -1835,8 +1841,6 @@ const struct efx_nic_type falcon_b0_nic_type = {
* interrupt handler only supports 32
* channels */
.timer_period_max = 1 << FRF_AB_TC_TIMER_VAL_WIDTH,
.tx_dc_base = 0x130000,
.rx_dc_base = 0x100000,
.offload_features = NETIF_F_IP_CSUM | NETIF_F_RXHASH | NETIF_F_NTUPLE,
};
......@@ -35,9 +35,17 @@
enum efx_filter_table_id {
EFX_FILTER_TABLE_RX_IP = 0,
EFX_FILTER_TABLE_RX_MAC,
EFX_FILTER_TABLE_RX_DEF,
EFX_FILTER_TABLE_TX_MAC,
EFX_FILTER_TABLE_COUNT,
};
enum efx_filter_index {
EFX_FILTER_INDEX_UC_DEF,
EFX_FILTER_INDEX_MC_DEF,
EFX_FILTER_SIZE_RX_DEF,
};
struct efx_filter_table {
enum efx_filter_table_id id;
u32 offset; /* address of table relative to BAR */
......@@ -90,8 +98,9 @@ efx_filter_spec_table_id(const struct efx_filter_spec *spec)
BUILD_BUG_ON(EFX_FILTER_TABLE_RX_IP != (EFX_FILTER_UDP_WILD >> 2));
BUILD_BUG_ON(EFX_FILTER_TABLE_RX_MAC != (EFX_FILTER_MAC_FULL >> 2));
BUILD_BUG_ON(EFX_FILTER_TABLE_RX_MAC != (EFX_FILTER_MAC_WILD >> 2));
BUILD_BUG_ON(EFX_FILTER_TABLE_TX_MAC != EFX_FILTER_TABLE_RX_MAC + 2);
EFX_BUG_ON_PARANOID(spec->type == EFX_FILTER_UNSPEC);
return spec->type >> 2;
return (spec->type >> 2) + ((spec->flags & EFX_FILTER_FLAG_TX) ? 2 : 0);
}
static struct efx_filter_table *
......@@ -109,7 +118,7 @@ static void efx_filter_table_reset_search_depth(struct efx_filter_table *table)
memset(table->search_depth, 0, sizeof(table->search_depth));
}
static void efx_filter_push_rx_limits(struct efx_nic *efx)
static void efx_filter_push_rx_config(struct efx_nic *efx)
{
struct efx_filter_state *state = efx->filter_state;
struct efx_filter_table *table;
......@@ -143,9 +152,58 @@ static void efx_filter_push_rx_limits(struct efx_nic *efx)
FILTER_CTL_SRCH_FUDGE_WILD);
}
table = &state->table[EFX_FILTER_TABLE_RX_DEF];
if (table->size) {
EFX_SET_OWORD_FIELD(
filter_ctl, FRF_CZ_UNICAST_NOMATCH_Q_ID,
table->spec[EFX_FILTER_INDEX_UC_DEF].dmaq_id);
EFX_SET_OWORD_FIELD(
filter_ctl, FRF_CZ_UNICAST_NOMATCH_RSS_ENABLED,
!!(table->spec[EFX_FILTER_INDEX_UC_DEF].flags &
EFX_FILTER_FLAG_RX_RSS));
EFX_SET_OWORD_FIELD(
filter_ctl, FRF_CZ_UNICAST_NOMATCH_IP_OVERRIDE,
!!(table->spec[EFX_FILTER_INDEX_UC_DEF].flags &
EFX_FILTER_FLAG_RX_OVERRIDE_IP));
EFX_SET_OWORD_FIELD(
filter_ctl, FRF_CZ_MULTICAST_NOMATCH_Q_ID,
table->spec[EFX_FILTER_INDEX_MC_DEF].dmaq_id);
EFX_SET_OWORD_FIELD(
filter_ctl, FRF_CZ_MULTICAST_NOMATCH_RSS_ENABLED,
!!(table->spec[EFX_FILTER_INDEX_MC_DEF].flags &
EFX_FILTER_FLAG_RX_RSS));
EFX_SET_OWORD_FIELD(
filter_ctl, FRF_CZ_MULTICAST_NOMATCH_IP_OVERRIDE,
!!(table->spec[EFX_FILTER_INDEX_MC_DEF].flags &
EFX_FILTER_FLAG_RX_OVERRIDE_IP));
}
efx_writeo(efx, &filter_ctl, FR_BZ_RX_FILTER_CTL);
}
static void efx_filter_push_tx_limits(struct efx_nic *efx)
{
struct efx_filter_state *state = efx->filter_state;
struct efx_filter_table *table;
efx_oword_t tx_cfg;
efx_reado(efx, &tx_cfg, FR_AZ_TX_CFG);
table = &state->table[EFX_FILTER_TABLE_TX_MAC];
if (table->size) {
EFX_SET_OWORD_FIELD(
tx_cfg, FRF_CZ_TX_ETH_FILTER_FULL_SEARCH_RANGE,
table->search_depth[EFX_FILTER_MAC_FULL] +
FILTER_CTL_SRCH_FUDGE_FULL);
EFX_SET_OWORD_FIELD(
tx_cfg, FRF_CZ_TX_ETH_FILTER_WILD_SEARCH_RANGE,
table->search_depth[EFX_FILTER_MAC_WILD] +
FILTER_CTL_SRCH_FUDGE_WILD);
}
efx_writeo(efx, &tx_cfg, FR_AZ_TX_CFG);
}
static inline void __efx_filter_set_ipv4(struct efx_filter_spec *spec,
__be32 host1, __be16 port1,
__be32 host2, __be16 port2)
......@@ -300,7 +358,8 @@ int efx_filter_get_ipv4_full(const struct efx_filter_spec *spec,
int efx_filter_set_eth_local(struct efx_filter_spec *spec,
u16 vid, const u8 *addr)
{
EFX_BUG_ON_PARANOID(!(spec->flags & EFX_FILTER_FLAG_RX));
EFX_BUG_ON_PARANOID(!(spec->flags &
(EFX_FILTER_FLAG_RX | EFX_FILTER_FLAG_TX)));
/* This cannot currently be combined with other filtering */
if (spec->type != EFX_FILTER_UNSPEC)
......@@ -319,6 +378,52 @@ int efx_filter_set_eth_local(struct efx_filter_spec *spec,
return 0;
}
/**
* efx_filter_set_uc_def - specify matching otherwise-unmatched unicast
* @spec: Specification to initialise
*/
int efx_filter_set_uc_def(struct efx_filter_spec *spec)
{
EFX_BUG_ON_PARANOID(!(spec->flags &
(EFX_FILTER_FLAG_RX | EFX_FILTER_FLAG_TX)));
if (spec->type != EFX_FILTER_UNSPEC)
return -EINVAL;
spec->type = EFX_FILTER_UC_DEF;
memset(spec->data, 0, sizeof(spec->data)); /* ensure equality */
return 0;
}
/**
* efx_filter_set_mc_def - specify matching otherwise-unmatched multicast
* @spec: Specification to initialise
*/
int efx_filter_set_mc_def(struct efx_filter_spec *spec)
{
EFX_BUG_ON_PARANOID(!(spec->flags &
(EFX_FILTER_FLAG_RX | EFX_FILTER_FLAG_TX)));
if (spec->type != EFX_FILTER_UNSPEC)
return -EINVAL;
spec->type = EFX_FILTER_MC_DEF;
memset(spec->data, 0, sizeof(spec->data)); /* ensure equality */
return 0;
}
static void efx_filter_reset_rx_def(struct efx_nic *efx, unsigned filter_idx)
{
struct efx_filter_state *state = efx->filter_state;
struct efx_filter_table *table = &state->table[EFX_FILTER_TABLE_RX_DEF];
struct efx_filter_spec *spec = &table->spec[filter_idx];
efx_filter_init_rx(spec, EFX_FILTER_PRI_MANUAL,
EFX_FILTER_FLAG_RX_RSS, 0);
spec->type = EFX_FILTER_UC_DEF + filter_idx;
table->used_bitmap[0] |= 1 << filter_idx;
}
int efx_filter_get_eth_local(const struct efx_filter_spec *spec,
u16 *vid, u8 *addr)
{
......@@ -366,6 +471,13 @@ static u32 efx_filter_build(efx_oword_t *filter, struct efx_filter_spec *spec)
break;
}
case EFX_FILTER_TABLE_RX_DEF:
/* One filter spec per type */
BUILD_BUG_ON(EFX_FILTER_INDEX_UC_DEF != 0);
BUILD_BUG_ON(EFX_FILTER_INDEX_MC_DEF !=
EFX_FILTER_MC_DEF - EFX_FILTER_UC_DEF);
return spec->type - EFX_FILTER_UC_DEF;
case EFX_FILTER_TABLE_RX_MAC: {
bool is_wild = spec->type == EFX_FILTER_MAC_WILD;
EFX_POPULATE_OWORD_8(
......@@ -385,6 +497,18 @@ static u32 efx_filter_build(efx_oword_t *filter, struct efx_filter_spec *spec)
break;
}
case EFX_FILTER_TABLE_TX_MAC: {
bool is_wild = spec->type == EFX_FILTER_MAC_WILD;
EFX_POPULATE_OWORD_5(*filter,
FRF_CZ_TMFT_TXQ_ID, spec->dmaq_id,
FRF_CZ_TMFT_WILDCARD_MATCH, is_wild,
FRF_CZ_TMFT_SRC_MAC_HI, spec->data[2],
FRF_CZ_TMFT_SRC_MAC_LO, spec->data[1],
FRF_CZ_TMFT_VLAN_ID, spec->data[0]);
data3 = is_wild | spec->dmaq_id << 1;
break;
}
default:
BUG();
}
......@@ -399,6 +523,10 @@ static bool efx_filter_equal(const struct efx_filter_spec *left,
memcmp(left->data, right->data, sizeof(left->data)))
return false;
if (left->flags & EFX_FILTER_FLAG_TX &&
left->dmaq_id != right->dmaq_id)
return false;
return true;
}
......@@ -448,23 +576,40 @@ static int efx_filter_search(struct efx_filter_table *table,
* MAC filters without overriding behaviour.
*/
#define EFX_FILTER_MATCH_PRI_RX_MAC_OVERRIDE_IP 0
#define EFX_FILTER_MATCH_PRI_RX_DEF_OVERRIDE_IP 1
#define EFX_FILTER_MATCH_PRI_NORMAL_BASE 2
#define EFX_FILTER_INDEX_WIDTH 13
#define EFX_FILTER_INDEX_MASK ((1 << EFX_FILTER_INDEX_WIDTH) - 1)
static inline u32 efx_filter_make_id(enum efx_filter_table_id table_id,
unsigned int index, u8 flags)
{
return (table_id == EFX_FILTER_TABLE_RX_MAC &&
flags & EFX_FILTER_FLAG_RX_OVERRIDE_IP) ?
index :
(table_id + 1) << EFX_FILTER_INDEX_WIDTH | index;
unsigned int match_pri = EFX_FILTER_MATCH_PRI_NORMAL_BASE + table_id;
if (flags & EFX_FILTER_FLAG_RX_OVERRIDE_IP) {
if (table_id == EFX_FILTER_TABLE_RX_MAC)
match_pri = EFX_FILTER_MATCH_PRI_RX_MAC_OVERRIDE_IP;
else if (table_id == EFX_FILTER_TABLE_RX_DEF)
match_pri = EFX_FILTER_MATCH_PRI_RX_DEF_OVERRIDE_IP;
}
return match_pri << EFX_FILTER_INDEX_WIDTH | index;
}
static inline enum efx_filter_table_id efx_filter_id_table_id(u32 id)
{
return (id <= EFX_FILTER_INDEX_MASK) ?
EFX_FILTER_TABLE_RX_MAC :
(id >> EFX_FILTER_INDEX_WIDTH) - 1;
unsigned int match_pri = id >> EFX_FILTER_INDEX_WIDTH;
switch (match_pri) {
case EFX_FILTER_MATCH_PRI_RX_MAC_OVERRIDE_IP:
return EFX_FILTER_TABLE_RX_MAC;
case EFX_FILTER_MATCH_PRI_RX_DEF_OVERRIDE_IP:
return EFX_FILTER_TABLE_RX_DEF;
default:
return match_pri - EFX_FILTER_MATCH_PRI_NORMAL_BASE;
}
}
static inline unsigned int efx_filter_id_index(u32 id)
......@@ -474,23 +619,30 @@ static inline unsigned int efx_filter_id_index(u32 id)
static inline u8 efx_filter_id_flags(u32 id)
{
return (id <= EFX_FILTER_INDEX_MASK) ?
EFX_FILTER_FLAG_RX | EFX_FILTER_FLAG_RX_OVERRIDE_IP :
EFX_FILTER_FLAG_RX;
unsigned int match_pri = id >> EFX_FILTER_INDEX_WIDTH;
if (match_pri < EFX_FILTER_MATCH_PRI_NORMAL_BASE)
return EFX_FILTER_FLAG_RX | EFX_FILTER_FLAG_RX_OVERRIDE_IP;
else if (match_pri <=
EFX_FILTER_MATCH_PRI_NORMAL_BASE + EFX_FILTER_TABLE_RX_DEF)
return EFX_FILTER_FLAG_RX;
else
return EFX_FILTER_FLAG_TX;
}
u32 efx_filter_get_rx_id_limit(struct efx_nic *efx)
{
struct efx_filter_state *state = efx->filter_state;
unsigned int table_id = EFX_FILTER_TABLE_RX_DEF;
if (state->table[EFX_FILTER_TABLE_RX_MAC].size != 0)
return ((EFX_FILTER_TABLE_RX_MAC + 1) << EFX_FILTER_INDEX_WIDTH)
+ state->table[EFX_FILTER_TABLE_RX_MAC].size;
else if (state->table[EFX_FILTER_TABLE_RX_IP].size != 0)
return ((EFX_FILTER_TABLE_RX_IP + 1) << EFX_FILTER_INDEX_WIDTH)
+ state->table[EFX_FILTER_TABLE_RX_IP].size;
else
return 0;
do {
if (state->table[table_id].size != 0)
return ((EFX_FILTER_MATCH_PRI_NORMAL_BASE + table_id)
<< EFX_FILTER_INDEX_WIDTH) +
state->table[table_id].size;
} while (table_id--);
return 0;
}
/**
......@@ -548,12 +700,20 @@ s32 efx_filter_insert_filter(struct efx_nic *efx, struct efx_filter_spec *spec,
}
*saved_spec = *spec;
if (table->search_depth[spec->type] < depth) {
table->search_depth[spec->type] = depth;
efx_filter_push_rx_limits(efx);
}
if (table->id == EFX_FILTER_TABLE_RX_DEF) {
efx_filter_push_rx_config(efx);
} else {
if (table->search_depth[spec->type] < depth) {
table->search_depth[spec->type] = depth;
if (spec->flags & EFX_FILTER_FLAG_TX)
efx_filter_push_tx_limits(efx);
else
efx_filter_push_rx_config(efx);
}
efx_writeo(efx, &filter, table->offset + table->step * filter_idx);
efx_writeo(efx, &filter,
table->offset + table->step * filter_idx);
}
netif_vdbg(efx, hw, efx->net_dev,
"%s: filter type %d index %d rxq %u set",
......@@ -571,7 +731,11 @@ static void efx_filter_table_clear_entry(struct efx_nic *efx,
{
static efx_oword_t filter;
if (test_bit(filter_idx, table->used_bitmap)) {
if (table->id == EFX_FILTER_TABLE_RX_DEF) {
/* RX default filters must always exist */
efx_filter_reset_rx_def(efx, filter_idx);
efx_filter_push_rx_config(efx);
} else if (test_bit(filter_idx, table->used_bitmap)) {
__clear_bit(filter_idx, table->used_bitmap);
--table->used;
memset(&table->spec[filter_idx], 0, sizeof(table->spec[0]));
......@@ -617,7 +781,8 @@ int efx_filter_remove_id_safe(struct efx_nic *efx,
spin_lock_bh(&state->lock);
if (test_bit(filter_idx, table->used_bitmap) &&
spec->priority == priority && spec->flags == filter_flags) {
spec->priority == priority &&
!((spec->flags ^ filter_flags) & EFX_FILTER_FLAG_RX_OVERRIDE_IP)) {
efx_filter_table_clear_entry(efx, table, filter_idx);
if (table->used == 0)
efx_filter_table_reset_search_depth(table);
......@@ -668,7 +833,8 @@ int efx_filter_get_filter_safe(struct efx_nic *efx,
spin_lock_bh(&state->lock);
if (test_bit(filter_idx, table->used_bitmap) &&
spec->priority == priority && spec->flags == filter_flags) {
spec->priority == priority &&
!((spec->flags ^ filter_flags) & EFX_FILTER_FLAG_RX_OVERRIDE_IP)) {
*spec_buf = *spec;
rc = 0;
} else {
......@@ -722,7 +888,7 @@ u32 efx_filter_count_rx_used(struct efx_nic *efx,
spin_lock_bh(&state->lock);
for (table_id = EFX_FILTER_TABLE_RX_IP;
table_id <= EFX_FILTER_TABLE_RX_MAC;
table_id <= EFX_FILTER_TABLE_RX_DEF;
table_id++) {
table = &state->table[table_id];
for (filter_idx = 0; filter_idx < table->size; filter_idx++) {
......@@ -750,7 +916,7 @@ s32 efx_filter_get_rx_ids(struct efx_nic *efx,
spin_lock_bh(&state->lock);
for (table_id = EFX_FILTER_TABLE_RX_IP;
table_id <= EFX_FILTER_TABLE_RX_MAC;
table_id <= EFX_FILTER_TABLE_RX_DEF;
table_id++) {
table = &state->table[table_id];
for (filter_idx = 0; filter_idx < table->size; filter_idx++) {
......@@ -785,6 +951,11 @@ void efx_restore_filters(struct efx_nic *efx)
for (table_id = 0; table_id < EFX_FILTER_TABLE_COUNT; table_id++) {
table = &state->table[table_id];
/* Check whether this is a regular register table */
if (table->step == 0)
continue;
for (filter_idx = 0; filter_idx < table->size; filter_idx++) {
if (!test_bit(filter_idx, table->used_bitmap))
continue;
......@@ -794,7 +965,8 @@ void efx_restore_filters(struct efx_nic *efx)
}
}
efx_filter_push_rx_limits(efx);
efx_filter_push_rx_config(efx);
efx_filter_push_tx_limits(efx);
spin_unlock_bh(&state->lock);
}
......@@ -833,6 +1005,16 @@ int efx_probe_filters(struct efx_nic *efx)
table->offset = FR_CZ_RX_MAC_FILTER_TBL0;
table->size = FR_CZ_RX_MAC_FILTER_TBL0_ROWS;
table->step = FR_CZ_RX_MAC_FILTER_TBL0_STEP;
table = &state->table[EFX_FILTER_TABLE_RX_DEF];
table->id = EFX_FILTER_TABLE_RX_DEF;
table->size = EFX_FILTER_SIZE_RX_DEF;
table = &state->table[EFX_FILTER_TABLE_TX_MAC];
table->id = EFX_FILTER_TABLE_TX_MAC;
table->offset = FR_CZ_TX_MAC_FILTER_TBL0;
table->size = FR_CZ_TX_MAC_FILTER_TBL0_ROWS;
table->step = FR_CZ_TX_MAC_FILTER_TBL0_STEP;
}
for (table_id = 0; table_id < EFX_FILTER_TABLE_COUNT; table_id++) {
......@@ -849,6 +1031,15 @@ int efx_probe_filters(struct efx_nic *efx)
goto fail;
}
if (state->table[EFX_FILTER_TABLE_RX_DEF].size) {
/* RX default filters must always exist */
unsigned i;
for (i = 0; i < EFX_FILTER_SIZE_RX_DEF; i++)
efx_filter_reset_rx_def(efx, i);
}
efx_filter_push_rx_config(efx);
return 0;
fail:
......
......@@ -20,6 +20,8 @@
* @EFX_FILTER_UDP_WILD: Matching UDP/IPv4 destination (host, port)
* @EFX_FILTER_MAC_FULL: Matching Ethernet destination MAC address, VID
* @EFX_FILTER_MAC_WILD: Matching Ethernet destination MAC address
* @EFX_FILTER_UC_DEF: Matching all otherwise unmatched unicast
* @EFX_FILTER_MC_DEF: Matching all otherwise unmatched multicast
* @EFX_FILTER_UNSPEC: Match type is unspecified
*
* Falcon NICs only support the TCP/IPv4 and UDP/IPv4 filter types.
......@@ -31,6 +33,8 @@ enum efx_filter_type {
EFX_FILTER_UDP_WILD,
EFX_FILTER_MAC_FULL = 4,
EFX_FILTER_MAC_WILD,
EFX_FILTER_UC_DEF = 8,
EFX_FILTER_MC_DEF,
EFX_FILTER_TYPE_COUNT, /* number of specific types */
EFX_FILTER_UNSPEC = 0xf,
};
......@@ -39,7 +43,8 @@ enum efx_filter_type {
* enum efx_filter_priority - priority of a hardware filter specification
* @EFX_FILTER_PRI_HINT: Performance hint
* @EFX_FILTER_PRI_MANUAL: Manually configured filter
* @EFX_FILTER_PRI_REQUIRED: Required for correct behaviour
* @EFX_FILTER_PRI_REQUIRED: Required for correct behaviour (user-level
* networking and SR-IOV)
*/
enum efx_filter_priority {
EFX_FILTER_PRI_HINT = 0,
......@@ -60,12 +65,14 @@ enum efx_filter_priority {
* any IP filter that matches the same packet. By default, IP
* filters take precedence.
* @EFX_FILTER_FLAG_RX: Filter is for RX
* @EFX_FILTER_FLAG_TX: Filter is for TX
*/
enum efx_filter_flags {
EFX_FILTER_FLAG_RX_RSS = 0x01,
EFX_FILTER_FLAG_RX_SCATTER = 0x02,
EFX_FILTER_FLAG_RX_OVERRIDE_IP = 0x04,
EFX_FILTER_FLAG_RX = 0x08,
EFX_FILTER_FLAG_TX = 0x10,
};
/**
......@@ -103,6 +110,15 @@ static inline void efx_filter_init_rx(struct efx_filter_spec *spec,
spec->dmaq_id = rxq_id;
}
static inline void efx_filter_init_tx(struct efx_filter_spec *spec,
unsigned txq_id)
{
spec->type = EFX_FILTER_UNSPEC;
spec->priority = EFX_FILTER_PRI_REQUIRED;
spec->flags = EFX_FILTER_FLAG_TX;
spec->dmaq_id = txq_id;
}
extern int efx_filter_set_ipv4_local(struct efx_filter_spec *spec, u8 proto,
__be32 host, __be16 port);
extern int efx_filter_get_ipv4_local(const struct efx_filter_spec *spec,
......@@ -117,6 +133,8 @@ extern int efx_filter_set_eth_local(struct efx_filter_spec *spec,
u16 vid, const u8 *addr);
extern int efx_filter_get_eth_local(const struct efx_filter_spec *spec,
u16 *vid, u8 *addr);
extern int efx_filter_set_uc_def(struct efx_filter_spec *spec);
extern int efx_filter_set_mc_def(struct efx_filter_spec *spec);
enum {
EFX_FILTER_VID_UNSPEC = 0xffff,
};
......
......@@ -560,6 +560,9 @@ void efx_mcdi_process_event(struct efx_channel *channel,
case MCDI_EVENT_CODE_MAC_STATS_DMA:
/* MAC stats are gather lazily. We can ignore this. */
break;
case MCDI_EVENT_CODE_FLR:
efx_sriov_flr(efx, MCDI_EVENT_FIELD(*event, FLR_VF));
break;
default:
netif_err(efx, hw, efx->net_dev, "Unknown MCDI event 0x%x\n",
......@@ -1154,6 +1157,37 @@ int efx_mcdi_wol_filter_remove(struct efx_nic *efx, int id)
return rc;
}
int efx_mcdi_flush_rxqs(struct efx_nic *efx)
{
struct efx_channel *channel;
struct efx_rx_queue *rx_queue;
__le32 *qid;
int rc, count;
qid = kmalloc(EFX_MAX_CHANNELS * sizeof(*qid), GFP_KERNEL);
if (qid == NULL)
return -ENOMEM;
count = 0;
efx_for_each_channel(channel, efx) {
efx_for_each_channel_rx_queue(rx_queue, channel) {
if (rx_queue->flush_pending) {
rx_queue->flush_pending = false;
atomic_dec(&efx->rxq_flush_pending);
qid[count++] = cpu_to_le32(
efx_rx_queue_index(rx_queue));
}
}
}
rc = efx_mcdi_rpc(efx, MC_CMD_FLUSH_RX_QUEUES, (u8 *)qid,
count * sizeof(*qid), NULL, 0, NULL);
WARN_ON(rc > 0);
kfree(qid);
return rc;
}
int efx_mcdi_wol_filter_reset(struct efx_nic *efx)
{
......
......@@ -146,6 +146,8 @@ 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_flush_rxqs(struct efx_nic *efx);
extern int efx_mcdi_set_mac(struct efx_nic *efx);
extern int efx_mcdi_mac_stats(struct efx_nic *efx, dma_addr_t dma_addr,
u32 dma_len, int enable, int clear);
extern int efx_mcdi_mac_reconfigure(struct efx_nic *efx);
......
......@@ -12,7 +12,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];
......@@ -44,6 +44,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);
......
......@@ -280,7 +280,7 @@ static int efx_mtd_probe_device(struct efx_nic *efx, struct efx_mtd *efx_mtd)
--part;
efx_mtd_remove_partition(part);
}
/* mtd_device_register() returns 1 if the MTD table is full */
/* Failure is unlikely here, but probably means we're out of memory */
return -ENOMEM;
}
......
......@@ -24,6 +24,7 @@
#include <linux/device.h>
#include <linux/highmem.h>
#include <linux/workqueue.h>
#include <linux/mutex.h>
#include <linux/vmalloc.h>
#include <linux/i2c.h>
......@@ -52,8 +53,10 @@
*
**************************************************************************/
#define EFX_MAX_CHANNELS 32
#define EFX_MAX_CHANNELS 32U
#define EFX_MAX_RX_QUEUES EFX_MAX_CHANNELS
#define EFX_EXTRA_CHANNEL_IOV 0
#define EFX_MAX_EXTRA_CHANNELS 1U
/* Checksum generation is a per-queue option in hardware, so each
* queue visible to the networking core is backed by two hardware TX
......@@ -81,15 +84,8 @@ struct efx_special_buffer {
void *addr;
dma_addr_t dma_addr;
unsigned int len;
int index;
int entries;
};
enum efx_flush_state {
FLUSH_NONE,
FLUSH_PENDING,
FLUSH_FAILED,
FLUSH_DONE,
unsigned int index;
unsigned int entries;
};
/**
......@@ -138,7 +134,6 @@ struct efx_tx_buffer {
* @txd: The hardware descriptor ring
* @ptr_mask: The size of the ring minus 1.
* @initialised: Has hardware queue been initialised?
* @flushed: Used when handling queue flushing
* @read_count: Current read pointer.
* This is the number of buffers that have been removed from both rings.
* @old_write_count: The value of @write_count when last checked.
......@@ -181,7 +176,6 @@ struct efx_tx_queue {
struct efx_special_buffer txd;
unsigned int ptr_mask;
bool initialised;
enum efx_flush_state flushed;
/* Members used mainly on the completion path */
unsigned int read_count ____cacheline_aligned_in_smp;
......@@ -249,6 +243,9 @@ struct efx_rx_page_state {
* @buffer: The software buffer ring
* @rxd: The hardware descriptor ring
* @ptr_mask: The size of the ring minus 1.
* @enabled: Receive queue enabled indicator.
* @flush_pending: Set when a RX flush is pending. Has the same lifetime as
* @rxq_flush_pending.
* @added_count: Number of buffers added to the receive queue.
* @notified_count: Number of buffers given to NIC (<= @added_count).
* @removed_count: Number of buffers removed from the receive queue.
......@@ -263,13 +260,14 @@ struct efx_rx_page_state {
* @alloc_page_count: RX allocation strategy counter.
* @alloc_skb_count: RX allocation strategy counter.
* @slow_fill: Timer used to defer efx_nic_generate_fill_event().
* @flushed: Use when handling queue flushing
*/
struct efx_rx_queue {
struct efx_nic *efx;
struct efx_rx_buffer *buffer;
struct efx_special_buffer rxd;
unsigned int ptr_mask;
bool enabled;
bool flush_pending;
int added_count;
int notified_count;
......@@ -283,8 +281,6 @@ struct efx_rx_queue {
unsigned int alloc_skb_count;
struct timer_list slow_fill;
unsigned int slow_fill_count;
enum efx_flush_state flushed;
};
/**
......@@ -318,6 +314,7 @@ enum efx_rx_alloc_method {
*
* @efx: Associated Efx NIC
* @channel: Channel instance number
* @type: Channel type definition
* @enabled: Channel enabled indicator
* @irq: IRQ number (MSI and MSI-X only)
* @irq_moderation: IRQ moderation value (in hardware ticks)
......@@ -348,6 +345,7 @@ enum efx_rx_alloc_method {
struct efx_channel {
struct efx_nic *efx;
int channel;
const struct efx_channel_type *type;
bool enabled;
int irq;
unsigned int irq_moderation;
......@@ -386,6 +384,26 @@ struct efx_channel {
struct efx_tx_queue tx_queue[EFX_TXQ_TYPES];
};
/**
* struct efx_channel_type - distinguishes traffic and extra channels
* @handle_no_channel: Handle failure to allocate an extra channel
* @pre_probe: Set up extra state prior to initialisation
* @post_remove: Tear down extra state after finalisation, if allocated.
* May be called on channels that have not been probed.
* @get_name: Generate the channel's name (used for its IRQ handler)
* @copy: Copy the channel state prior to reallocation. May be %NULL if
* reallocation is not supported.
* @keep_eventq: Flag for whether event queue should be kept initialised
* while the device is stopped
*/
struct efx_channel_type {
void (*handle_no_channel)(struct efx_nic *);
int (*pre_probe)(struct efx_channel *);
void (*get_name)(struct efx_channel *, char *buf, size_t len);
struct efx_channel *(*copy)(const struct efx_channel *);
bool keep_eventq;
};
enum efx_led_mode {
EFX_LED_OFF = 0,
EFX_LED_ON = 1,
......@@ -613,6 +631,8 @@ union efx_multicast_hash {
};
struct efx_filter_state;
struct efx_vf;
struct vfdi_status;
/**
* struct efx_nic - an Efx NIC
......@@ -638,8 +658,13 @@ struct efx_filter_state;
* @rx_queue: RX DMA queues
* @channel: Channels
* @channel_name: Names for channels and their IRQs
* @extra_channel_types: Types of extra (non-traffic) channels that
* should be allocated for this NIC
* @rxq_entries: Size of receive queues requested by user.
* @txq_entries: Size of transmit queues requested by user.
* @tx_dc_base: Base qword address in SRAM of TX queue descriptor caches
* @rx_dc_base: Base qword address in SRAM of RX queue descriptor caches
* @sram_lim_qw: Qword address limit of SRAM
* @next_buffer_table: First available buffer table id
* @n_channels: Number of channels in use
* @n_rx_channels: Number of channels used for RX (= number of RX queues)
......@@ -677,10 +702,31 @@ 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
* @loopback_selftest: Offline self-test private state
* @drain_pending: Count of RX and TX queues that haven't been flushed and drained.
* @rxq_flush_pending: Count of number of receive queues that need to be flushed.
* Decremented when the efx_flush_rx_queue() is called.
* @rxq_flush_outstanding: Count of number of RX flushes started but not yet
* completed (either success or failure). Not used when MCDI is used to
* flush receive queues.
* @flush_wq: wait queue used by efx_nic_flush_queues() to wait for flush completions.
* @vf: Array of &struct efx_vf objects.
* @vf_count: Number of VFs intended to be enabled.
* @vf_init_count: Number of VFs that have been fully initialised.
* @vi_scale: log2 number of vnics per VF.
* @vf_buftbl_base: The zeroth buffer table index used to back VF queues.
* @vfdi_status: Common VFDI status page to be dmad to VF address space.
* @local_addr_list: List of local addresses. Protected by %local_lock.
* @local_page_list: List of DMA addressable pages used to broadcast
* %local_addr_list. Protected by %local_lock.
* @local_lock: Mutex protecting %local_addr_list and %local_page_list.
* @peer_work: Work item to broadcast peer addresses to VMs.
* @monitor_work: Hardware monitor workitem
* @biu_lock: BIU (bus interface unit) lock
* @last_irq_cpu: Last CPU to handle a possible test interrupt. This
......@@ -720,12 +766,18 @@ struct efx_nic {
struct efx_channel *channel[EFX_MAX_CHANNELS];
char channel_name[EFX_MAX_CHANNELS][IFNAMSIZ + 6];
const struct efx_channel_type *
extra_channel_type[EFX_MAX_EXTRA_CHANNELS];
unsigned rxq_entries;
unsigned txq_entries;
unsigned tx_dc_base;
unsigned rx_dc_base;
unsigned sram_lim_qw;
unsigned next_buffer_table;
unsigned n_channels;
unsigned n_rx_channels;
unsigned rss_spread;
unsigned tx_channel_offset;
unsigned n_tx_channels;
unsigned int rx_buffer_len;
......@@ -769,6 +821,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;
......@@ -778,6 +831,25 @@ struct efx_nic {
struct efx_filter_state *filter_state;
atomic_t drain_pending;
atomic_t rxq_flush_pending;
atomic_t rxq_flush_outstanding;
wait_queue_head_t flush_wq;
#ifdef CONFIG_SFC_SRIOV
struct efx_channel *vfdi_channel;
struct efx_vf *vf;
unsigned vf_count;
unsigned vf_init_count;
unsigned vi_scale;
unsigned vf_buftbl_base;
struct efx_buffer vfdi_status;
struct list_head local_addr_list;
struct list_head local_page_list;
struct mutex local_lock;
struct work_struct peer_work;
#endif
/* The following fields may be written more often */
struct delayed_work monitor_work ____cacheline_aligned_in_smp;
......@@ -803,6 +875,8 @@ static inline unsigned int efx_port_num(struct efx_nic *efx)
* @probe: Probe the controller
* @remove: Free resources allocated by probe()
* @init: Initialise the controller
* @dimension_resources: Dimension controller resources (buffer table,
* and VIs once the available interrupt resources are clear)
* @fini: Shut down the controller
* @monitor: Periodic function for polling link state and hardware monitor
* @map_reset_reason: Map ethtool reset reason to a reset method
......@@ -842,8 +916,6 @@ static inline unsigned int efx_port_num(struct efx_nic *efx)
* @phys_addr_channels: Number of channels with physically addressed
* descriptors
* @timer_period_max: Maximum period of interrupt timer (in ticks)
* @tx_dc_base: Base address in SRAM of TX queue descriptor caches
* @rx_dc_base: Base address in SRAM of RX queue descriptor caches
* @offload_features: net_device feature flags for protocol offload
* features implemented in hardware
*/
......@@ -851,6 +923,7 @@ struct efx_nic_type {
int (*probe)(struct efx_nic *efx);
void (*remove)(struct efx_nic *efx);
int (*init)(struct efx_nic *efx);
void (*dimension_resources)(struct efx_nic *efx);
void (*fini)(struct efx_nic *efx);
void (*monitor)(struct efx_nic *efx);
enum reset_type (*map_reset_reason)(enum reset_type reason);
......@@ -887,8 +960,6 @@ struct efx_nic_type {
unsigned int max_interrupt_mode;
unsigned int phys_addr_channels;
unsigned int timer_period_max;
unsigned int tx_dc_base;
unsigned int rx_dc_base;
netdev_features_t offload_features;
};
......@@ -912,6 +983,13 @@ efx_get_channel(struct efx_nic *efx, unsigned index)
_channel = (_channel->channel + 1 < (_efx)->n_channels) ? \
(_efx)->channel[_channel->channel + 1] : NULL)
/* Iterate over all used channels in reverse */
#define efx_for_each_channel_rev(_channel, _efx) \
for (_channel = (_efx)->channel[(_efx)->n_channels - 1]; \
_channel; \
_channel = _channel->channel ? \
(_efx)->channel[_channel->channel - 1] : NULL)
static inline struct efx_tx_queue *
efx_get_tx_queue(struct efx_nic *efx, unsigned index, unsigned type)
{
......@@ -956,13 +1034,6 @@ static inline bool efx_tx_queue_used(struct efx_tx_queue *tx_queue)
_tx_queue < (_channel)->tx_queue + EFX_TXQ_TYPES; \
_tx_queue++)
static inline struct efx_rx_queue *
efx_get_rx_queue(struct efx_nic *efx, unsigned index)
{
EFX_BUG_ON_PARANOID(index >= efx->n_rx_channels);
return &efx->channel[index]->rx_queue;
}
static inline bool efx_channel_has_rx_queue(struct efx_channel *channel)
{
return channel->channel < channel->efx->n_rx_channels;
......
......@@ -49,24 +49,29 @@
#define EFX_INT_ERROR_EXPIRE 3600
#define EFX_MAX_INT_ERRORS 5
/* We poll for events every FLUSH_INTERVAL ms, and check FLUSH_POLL_COUNT times
*/
#define EFX_FLUSH_INTERVAL 10
#define EFX_FLUSH_POLL_COUNT 100
/* Size and alignment of special buffers (4KB) */
#define EFX_BUF_SIZE 4096
/* Depth of RX flush request fifo */
#define EFX_RX_FLUSH_COUNT 4
/* Generated event code for efx_generate_test_event() */
#define EFX_CHANNEL_MAGIC_TEST(_channel) \
(0x00010100 + (_channel)->channel)
/* Generated event code for efx_generate_fill_event() */
#define EFX_CHANNEL_MAGIC_FILL(_channel) \
(0x00010200 + (_channel)->channel)
/* Driver generated events */
#define _EFX_CHANNEL_MAGIC_TEST 0x000101
#define _EFX_CHANNEL_MAGIC_FILL 0x000102
#define _EFX_CHANNEL_MAGIC_RX_DRAIN 0x000103
#define _EFX_CHANNEL_MAGIC_TX_DRAIN 0x000104
#define _EFX_CHANNEL_MAGIC(_code, _data) ((_code) << 8 | (_data))
#define _EFX_CHANNEL_MAGIC_CODE(_magic) ((_magic) >> 8)
#define EFX_CHANNEL_MAGIC_TEST(_channel) \
_EFX_CHANNEL_MAGIC(_EFX_CHANNEL_MAGIC_TEST, (_channel)->channel)
#define EFX_CHANNEL_MAGIC_FILL(_rx_queue) \
_EFX_CHANNEL_MAGIC(_EFX_CHANNEL_MAGIC_FILL, \
efx_rx_queue_index(_rx_queue))
#define EFX_CHANNEL_MAGIC_RX_DRAIN(_rx_queue) \
_EFX_CHANNEL_MAGIC(_EFX_CHANNEL_MAGIC_RX_DRAIN, \
efx_rx_queue_index(_rx_queue))
#define EFX_CHANNEL_MAGIC_TX_DRAIN(_tx_queue) \
_EFX_CHANNEL_MAGIC(_EFX_CHANNEL_MAGIC_TX_DRAIN, \
(_tx_queue)->queue)
/**************************************************************************
*
......@@ -187,7 +192,7 @@ static void
efx_init_special_buffer(struct efx_nic *efx, struct efx_special_buffer *buffer)
{
efx_qword_t buf_desc;
int index;
unsigned int index;
dma_addr_t dma_addr;
int i;
......@@ -196,7 +201,7 @@ efx_init_special_buffer(struct efx_nic *efx, struct efx_special_buffer *buffer)
/* Write buffer descriptors to NIC */
for (i = 0; i < buffer->entries; i++) {
index = buffer->index + i;
dma_addr = buffer->dma_addr + (i * 4096);
dma_addr = buffer->dma_addr + (i * EFX_BUF_SIZE);
netif_dbg(efx, probe, efx->net_dev,
"mapping special buffer %d at %llx\n",
index, (unsigned long long)dma_addr);
......@@ -259,6 +264,10 @@ static int efx_alloc_special_buffer(struct efx_nic *efx,
/* Select new buffer ID */
buffer->index = efx->next_buffer_table;
efx->next_buffer_table += buffer->entries;
#ifdef CONFIG_SFC_SRIOV
BUG_ON(efx_sriov_enabled(efx) &&
efx->vf_buftbl_base < efx->next_buffer_table);
#endif
netif_dbg(efx, probe, efx->net_dev,
"allocating special buffers %d-%d at %llx+%x "
......@@ -430,8 +439,6 @@ void efx_nic_init_tx(struct efx_tx_queue *tx_queue)
struct efx_nic *efx = tx_queue->efx;
efx_oword_t reg;
tx_queue->flushed = FLUSH_NONE;
/* Pin TX descriptor ring */
efx_init_special_buffer(efx, &tx_queue->txd);
......@@ -488,9 +495,6 @@ static void efx_flush_tx_queue(struct efx_tx_queue *tx_queue)
struct efx_nic *efx = tx_queue->efx;
efx_oword_t tx_flush_descq;
tx_queue->flushed = FLUSH_PENDING;
/* Post a flush command */
EFX_POPULATE_OWORD_2(tx_flush_descq,
FRF_AZ_TX_FLUSH_DESCQ_CMD, 1,
FRF_AZ_TX_FLUSH_DESCQ, tx_queue->queue);
......@@ -502,9 +506,6 @@ void efx_nic_fini_tx(struct efx_tx_queue *tx_queue)
struct efx_nic *efx = tx_queue->efx;
efx_oword_t tx_desc_ptr;
/* The queue should have been flushed */
WARN_ON(tx_queue->flushed != FLUSH_DONE);
/* Remove TX descriptor ring from card */
EFX_ZERO_OWORD(tx_desc_ptr);
efx_writeo_table(efx, &tx_desc_ptr, efx->type->txd_ptr_tbl_base,
......@@ -595,8 +596,6 @@ void efx_nic_init_rx(struct efx_rx_queue *rx_queue)
efx_rx_queue_index(rx_queue), rx_queue->rxd.index,
rx_queue->rxd.index + rx_queue->rxd.entries - 1);
rx_queue->flushed = FLUSH_NONE;
/* Pin RX descriptor ring */
efx_init_special_buffer(efx, &rx_queue->rxd);
......@@ -625,9 +624,6 @@ static void efx_flush_rx_queue(struct efx_rx_queue *rx_queue)
struct efx_nic *efx = rx_queue->efx;
efx_oword_t rx_flush_descq;
rx_queue->flushed = FLUSH_PENDING;
/* Post a flush command */
EFX_POPULATE_OWORD_2(rx_flush_descq,
FRF_AZ_RX_FLUSH_DESCQ_CMD, 1,
FRF_AZ_RX_FLUSH_DESCQ,
......@@ -640,9 +636,6 @@ void efx_nic_fini_rx(struct efx_rx_queue *rx_queue)
efx_oword_t rx_desc_ptr;
struct efx_nic *efx = rx_queue->efx;
/* The queue should already have been flushed */
WARN_ON(rx_queue->flushed != FLUSH_DONE);
/* Remove RX descriptor ring from card */
EFX_ZERO_OWORD(rx_desc_ptr);
efx_writeo_table(efx, &rx_desc_ptr, efx->type->rxd_ptr_tbl_base,
......@@ -658,6 +651,103 @@ void efx_nic_remove_rx(struct efx_rx_queue *rx_queue)
efx_free_special_buffer(rx_queue->efx, &rx_queue->rxd);
}
/**************************************************************************
*
* Flush handling
*
**************************************************************************/
/* efx_nic_flush_queues() must be woken up when all flushes are completed,
* or more RX flushes can be kicked off.
*/
static bool efx_flush_wake(struct efx_nic *efx)
{
/* Ensure that all updates are visible to efx_nic_flush_queues() */
smp_mb();
return (atomic_read(&efx->drain_pending) == 0 ||
(atomic_read(&efx->rxq_flush_outstanding) < EFX_RX_FLUSH_COUNT
&& atomic_read(&efx->rxq_flush_pending) > 0));
}
/* Flush all the transmit queues, and continue flushing receive queues until
* they're all flushed. Wait for the DRAIN events to be recieved so that there
* are no more RX and TX events left on any channel. */
int efx_nic_flush_queues(struct efx_nic *efx)
{
unsigned timeout = msecs_to_jiffies(5000); /* 5s for all flushes and drains */
struct efx_channel *channel;
struct efx_rx_queue *rx_queue;
struct efx_tx_queue *tx_queue;
int rc = 0;
efx->fc_disable++;
efx->type->prepare_flush(efx);
efx_for_each_channel(channel, efx) {
efx_for_each_channel_tx_queue(tx_queue, channel) {
atomic_inc(&efx->drain_pending);
efx_flush_tx_queue(tx_queue);
}
efx_for_each_channel_rx_queue(rx_queue, channel) {
atomic_inc(&efx->drain_pending);
rx_queue->flush_pending = true;
atomic_inc(&efx->rxq_flush_pending);
}
}
while (timeout && atomic_read(&efx->drain_pending) > 0) {
/* If SRIOV is enabled, then offload receive queue flushing to
* the firmware (though we will still have to poll for
* completion). If that fails, fall back to the old scheme.
*/
if (efx_sriov_enabled(efx)) {
rc = efx_mcdi_flush_rxqs(efx);
if (!rc)
goto wait;
}
/* The hardware supports four concurrent rx flushes, each of
* which may need to be retried if there is an outstanding
* descriptor fetch
*/
efx_for_each_channel(channel, efx) {
efx_for_each_channel_rx_queue(rx_queue, channel) {
if (atomic_read(&efx->rxq_flush_outstanding) >=
EFX_RX_FLUSH_COUNT)
break;
if (rx_queue->flush_pending) {
rx_queue->flush_pending = false;
atomic_dec(&efx->rxq_flush_pending);
atomic_inc(&efx->rxq_flush_outstanding);
efx_flush_rx_queue(rx_queue);
}
}
}
wait:
timeout = wait_event_timeout(efx->flush_wq, efx_flush_wake(efx),
timeout);
}
if (atomic_read(&efx->drain_pending)) {
netif_err(efx, hw, efx->net_dev, "failed to flush %d queues "
"(rx %d+%d)\n", atomic_read(&efx->drain_pending),
atomic_read(&efx->rxq_flush_outstanding),
atomic_read(&efx->rxq_flush_pending));
rc = -ETIMEDOUT;
atomic_set(&efx->drain_pending, 0);
atomic_set(&efx->rxq_flush_pending, 0);
atomic_set(&efx->rxq_flush_outstanding, 0);
}
efx->fc_disable--;
return rc;
}
/**************************************************************************
*
* Event queue processing
......@@ -682,7 +772,8 @@ void efx_nic_eventq_read_ack(struct efx_channel *channel)
}
/* Use HW to insert a SW defined event */
static void efx_generate_event(struct efx_channel *channel, efx_qword_t *event)
void efx_generate_event(struct efx_nic *efx, unsigned int evq,
efx_qword_t *event)
{
efx_oword_t drv_ev_reg;
......@@ -692,8 +783,18 @@ static void efx_generate_event(struct efx_channel *channel, efx_qword_t *event)
drv_ev_reg.u32[1] = event->u32[1];
drv_ev_reg.u32[2] = 0;
drv_ev_reg.u32[3] = 0;
EFX_SET_OWORD_FIELD(drv_ev_reg, FRF_AZ_DRV_EV_QID, channel->channel);
efx_writeo(channel->efx, &drv_ev_reg, FR_AZ_DRV_EV);
EFX_SET_OWORD_FIELD(drv_ev_reg, FRF_AZ_DRV_EV_QID, evq);
efx_writeo(efx, &drv_ev_reg, FR_AZ_DRV_EV);
}
static void efx_magic_event(struct efx_channel *channel, u32 magic)
{
efx_qword_t event;
EFX_POPULATE_QWORD_2(event, FSF_AZ_EV_CODE,
FSE_AZ_EV_CODE_DRV_GEN_EV,
FSF_AZ_DRV_GEN_EV_MAGIC, magic);
efx_generate_event(channel->efx, channel->channel, &event);
}
/* Handle a transmit completion event
......@@ -710,6 +811,9 @@ efx_handle_tx_event(struct efx_channel *channel, efx_qword_t *event)
struct efx_nic *efx = channel->efx;
int tx_packets = 0;
if (unlikely(ACCESS_ONCE(efx->reset_pending)))
return 0;
if (likely(EFX_QWORD_FIELD(*event, FSF_AZ_TX_EV_COMP))) {
/* Transmit completion */
tx_ev_desc_ptr = EFX_QWORD_FIELD(*event, FSF_AZ_TX_EV_DESC_PTR);
......@@ -851,6 +955,10 @@ efx_handle_rx_event(struct efx_channel *channel, const efx_qword_t *event)
bool rx_ev_pkt_ok;
u16 flags;
struct efx_rx_queue *rx_queue;
struct efx_nic *efx = channel->efx;
if (unlikely(ACCESS_ONCE(efx->reset_pending)))
return;
/* Basic packet information */
rx_ev_byte_cnt = EFX_QWORD_FIELD(*event, FSF_AZ_RX_EV_BYTE_CNT);
......@@ -897,24 +1005,101 @@ efx_handle_rx_event(struct efx_channel *channel, const efx_qword_t *event)
efx_rx_packet(rx_queue, rx_ev_desc_ptr, rx_ev_byte_cnt, flags);
}
/* If this flush done event corresponds to a &struct efx_tx_queue, then
* send an %EFX_CHANNEL_MAGIC_TX_DRAIN event to drain the event queue
* of all transmit completions.
*/
static void
efx_handle_tx_flush_done(struct efx_nic *efx, efx_qword_t *event)
{
struct efx_tx_queue *tx_queue;
int qid;
qid = EFX_QWORD_FIELD(*event, FSF_AZ_DRIVER_EV_SUBDATA);
if (qid < EFX_TXQ_TYPES * efx->n_tx_channels) {
tx_queue = efx_get_tx_queue(efx, qid / EFX_TXQ_TYPES,
qid % EFX_TXQ_TYPES);
efx_magic_event(tx_queue->channel,
EFX_CHANNEL_MAGIC_TX_DRAIN(tx_queue));
}
}
/* If this flush done event corresponds to a &struct efx_rx_queue: If the flush
* was succesful then send an %EFX_CHANNEL_MAGIC_RX_DRAIN, otherwise add
* the RX queue back to the mask of RX queues in need of flushing.
*/
static void
efx_handle_rx_flush_done(struct efx_nic *efx, efx_qword_t *event)
{
struct efx_channel *channel;
struct efx_rx_queue *rx_queue;
int qid;
bool failed;
qid = EFX_QWORD_FIELD(*event, FSF_AZ_DRIVER_EV_RX_DESCQ_ID);
failed = EFX_QWORD_FIELD(*event, FSF_AZ_DRIVER_EV_RX_FLUSH_FAIL);
if (qid >= efx->n_channels)
return;
channel = efx_get_channel(efx, qid);
if (!efx_channel_has_rx_queue(channel))
return;
rx_queue = efx_channel_get_rx_queue(channel);
if (failed) {
netif_info(efx, hw, efx->net_dev,
"RXQ %d flush retry\n", qid);
rx_queue->flush_pending = true;
atomic_inc(&efx->rxq_flush_pending);
} else {
efx_magic_event(efx_rx_queue_channel(rx_queue),
EFX_CHANNEL_MAGIC_RX_DRAIN(rx_queue));
}
atomic_dec(&efx->rxq_flush_outstanding);
if (efx_flush_wake(efx))
wake_up(&efx->flush_wq);
}
static void
efx_handle_drain_event(struct efx_channel *channel)
{
struct efx_nic *efx = channel->efx;
WARN_ON(atomic_read(&efx->drain_pending) == 0);
atomic_dec(&efx->drain_pending);
if (efx_flush_wake(efx))
wake_up(&efx->flush_wq);
}
static void
efx_handle_generated_event(struct efx_channel *channel, efx_qword_t *event)
{
struct efx_nic *efx = channel->efx;
unsigned code;
struct efx_rx_queue *rx_queue =
efx_channel_has_rx_queue(channel) ?
efx_channel_get_rx_queue(channel) : NULL;
unsigned magic, code;
magic = EFX_QWORD_FIELD(*event, FSF_AZ_DRV_GEN_EV_MAGIC);
code = _EFX_CHANNEL_MAGIC_CODE(magic);
code = EFX_QWORD_FIELD(*event, FSF_AZ_DRV_GEN_EV_MAGIC);
if (code == EFX_CHANNEL_MAGIC_TEST(channel))
; /* ignore */
else if (code == EFX_CHANNEL_MAGIC_FILL(channel))
if (magic == EFX_CHANNEL_MAGIC_TEST(channel)) {
/* ignore */
} else if (rx_queue && magic == EFX_CHANNEL_MAGIC_FILL(rx_queue)) {
/* 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(efx_channel_get_rx_queue(channel));
else
efx_fast_push_rx_descriptors(rx_queue);
} else if (rx_queue && magic == EFX_CHANNEL_MAGIC_RX_DRAIN(rx_queue)) {
rx_queue->enabled = false;
efx_handle_drain_event(channel);
} else if (code == _EFX_CHANNEL_MAGIC_TX_DRAIN) {
efx_handle_drain_event(channel);
} else {
netif_dbg(efx, hw, efx->net_dev, "channel %d received "
"generated event "EFX_QWORD_FMT"\n",
channel->channel, EFX_QWORD_VAL(*event));
}
}
static void
......@@ -931,10 +1116,14 @@ efx_handle_driver_event(struct efx_channel *channel, efx_qword_t *event)
case FSE_AZ_TX_DESCQ_FLS_DONE_EV:
netif_vdbg(efx, hw, efx->net_dev, "channel %d TXQ %d flushed\n",
channel->channel, ev_sub_data);
efx_handle_tx_flush_done(efx, event);
efx_sriov_tx_flush_done(efx, event);
break;
case FSE_AZ_RX_DESCQ_FLS_DONE_EV:
netif_vdbg(efx, hw, efx->net_dev, "channel %d RXQ %d flushed\n",
channel->channel, ev_sub_data);
efx_handle_rx_flush_done(efx, event);
efx_sriov_rx_flush_done(efx, event);
break;
case FSE_AZ_EVQ_INIT_DONE_EV:
netif_dbg(efx, hw, efx->net_dev,
......@@ -966,16 +1155,24 @@ efx_handle_driver_event(struct efx_channel *channel, efx_qword_t *event)
RESET_TYPE_DISABLE);
break;
case FSE_BZ_RX_DSC_ERROR_EV:
netif_err(efx, rx_err, efx->net_dev,
"RX DMA Q %d reports descriptor fetch error."
" RX Q %d is disabled.\n", ev_sub_data, ev_sub_data);
efx_schedule_reset(efx, RESET_TYPE_RX_DESC_FETCH);
if (ev_sub_data < EFX_VI_BASE) {
netif_err(efx, rx_err, efx->net_dev,
"RX DMA Q %d reports descriptor fetch error."
" RX Q %d is disabled.\n", ev_sub_data,
ev_sub_data);
efx_schedule_reset(efx, RESET_TYPE_RX_DESC_FETCH);
} else
efx_sriov_desc_fetch_err(efx, ev_sub_data);
break;
case FSE_BZ_TX_DSC_ERROR_EV:
netif_err(efx, tx_err, efx->net_dev,
"TX DMA Q %d reports descriptor fetch error."
" TX Q %d is disabled.\n", ev_sub_data, ev_sub_data);
efx_schedule_reset(efx, RESET_TYPE_TX_DESC_FETCH);
if (ev_sub_data < EFX_VI_BASE) {
netif_err(efx, tx_err, efx->net_dev,
"TX DMA Q %d reports descriptor fetch error."
" TX Q %d is disabled.\n", ev_sub_data,
ev_sub_data);
efx_schedule_reset(efx, RESET_TYPE_TX_DESC_FETCH);
} else
efx_sriov_desc_fetch_err(efx, ev_sub_data);
break;
default:
netif_vdbg(efx, hw, efx->net_dev,
......@@ -1035,6 +1232,9 @@ int efx_nic_process_eventq(struct efx_channel *channel, int budget)
case FSE_AZ_EV_CODE_DRIVER_EV:
efx_handle_driver_event(channel, &event);
break;
case FSE_CZ_EV_CODE_USER_EV:
efx_sriov_event(channel, &event);
break;
case FSE_CZ_EV_CODE_MCDI_EV:
efx_mcdi_process_event(channel, &event);
break;
......@@ -1135,161 +1335,13 @@ void efx_nic_remove_eventq(struct efx_channel *channel)
void efx_nic_generate_test_event(struct efx_channel *channel)
{
unsigned int magic = EFX_CHANNEL_MAGIC_TEST(channel);
efx_qword_t test_event;
EFX_POPULATE_QWORD_2(test_event, FSF_AZ_EV_CODE,
FSE_AZ_EV_CODE_DRV_GEN_EV,
FSF_AZ_DRV_GEN_EV_MAGIC, magic);
efx_generate_event(channel, &test_event);
}
void efx_nic_generate_fill_event(struct efx_channel *channel)
{
unsigned int magic = EFX_CHANNEL_MAGIC_FILL(channel);
efx_qword_t test_event;
EFX_POPULATE_QWORD_2(test_event, FSF_AZ_EV_CODE,
FSE_AZ_EV_CODE_DRV_GEN_EV,
FSF_AZ_DRV_GEN_EV_MAGIC, magic);
efx_generate_event(channel, &test_event);
efx_magic_event(channel, EFX_CHANNEL_MAGIC_TEST(channel));
}
/**************************************************************************
*
* Flush handling
*
**************************************************************************/
static void efx_poll_flush_events(struct efx_nic *efx)
{
struct efx_channel *channel = efx_get_channel(efx, 0);
struct efx_tx_queue *tx_queue;
struct efx_rx_queue *rx_queue;
unsigned int read_ptr = channel->eventq_read_ptr;
unsigned int end_ptr = read_ptr + channel->eventq_mask - 1;
do {
efx_qword_t *event = efx_event(channel, read_ptr);
int ev_code, ev_sub_code, ev_queue;
bool ev_failed;
if (!efx_event_present(event))
break;
ev_code = EFX_QWORD_FIELD(*event, FSF_AZ_EV_CODE);
ev_sub_code = EFX_QWORD_FIELD(*event,
FSF_AZ_DRIVER_EV_SUBCODE);
if (ev_code == FSE_AZ_EV_CODE_DRIVER_EV &&
ev_sub_code == FSE_AZ_TX_DESCQ_FLS_DONE_EV) {
ev_queue = EFX_QWORD_FIELD(*event,
FSF_AZ_DRIVER_EV_SUBDATA);
if (ev_queue < EFX_TXQ_TYPES * efx->n_tx_channels) {
tx_queue = efx_get_tx_queue(
efx, ev_queue / EFX_TXQ_TYPES,
ev_queue % EFX_TXQ_TYPES);
tx_queue->flushed = FLUSH_DONE;
}
} else if (ev_code == FSE_AZ_EV_CODE_DRIVER_EV &&
ev_sub_code == FSE_AZ_RX_DESCQ_FLS_DONE_EV) {
ev_queue = EFX_QWORD_FIELD(
*event, FSF_AZ_DRIVER_EV_RX_DESCQ_ID);
ev_failed = EFX_QWORD_FIELD(
*event, FSF_AZ_DRIVER_EV_RX_FLUSH_FAIL);
if (ev_queue < efx->n_rx_channels) {
rx_queue = efx_get_rx_queue(efx, ev_queue);
rx_queue->flushed =
ev_failed ? FLUSH_FAILED : FLUSH_DONE;
}
}
/* We're about to destroy the queue anyway, so
* it's ok to throw away every non-flush event */
EFX_SET_QWORD(*event);
++read_ptr;
} while (read_ptr != end_ptr);
channel->eventq_read_ptr = read_ptr;
}
/* Handle tx and rx flushes at the same time, since they run in
* parallel in the hardware and there's no reason for us to
* serialise them */
int efx_nic_flush_queues(struct efx_nic *efx)
void efx_nic_generate_fill_event(struct efx_rx_queue *rx_queue)
{
struct efx_channel *channel;
struct efx_rx_queue *rx_queue;
struct efx_tx_queue *tx_queue;
int i, tx_pending, rx_pending;
/* If necessary prepare the hardware for flushing */
efx->type->prepare_flush(efx);
/* Flush all tx queues in parallel */
efx_for_each_channel(channel, efx) {
efx_for_each_possible_channel_tx_queue(tx_queue, channel) {
if (tx_queue->initialised)
efx_flush_tx_queue(tx_queue);
}
}
/* The hardware supports four concurrent rx flushes, each of which may
* need to be retried if there is an outstanding descriptor fetch */
for (i = 0; i < EFX_FLUSH_POLL_COUNT; ++i) {
rx_pending = tx_pending = 0;
efx_for_each_channel(channel, efx) {
efx_for_each_channel_rx_queue(rx_queue, channel) {
if (rx_queue->flushed == FLUSH_PENDING)
++rx_pending;
}
}
efx_for_each_channel(channel, efx) {
efx_for_each_channel_rx_queue(rx_queue, channel) {
if (rx_pending == EFX_RX_FLUSH_COUNT)
break;
if (rx_queue->flushed == FLUSH_FAILED ||
rx_queue->flushed == FLUSH_NONE) {
efx_flush_rx_queue(rx_queue);
++rx_pending;
}
}
efx_for_each_possible_channel_tx_queue(tx_queue, channel) {
if (tx_queue->initialised &&
tx_queue->flushed != FLUSH_DONE)
++tx_pending;
}
}
if (rx_pending == 0 && tx_pending == 0)
return 0;
msleep(EFX_FLUSH_INTERVAL);
efx_poll_flush_events(efx);
}
/* Mark the queues as all flushed. We're going to return failure
* leading to a reset, or fake up success anyway */
efx_for_each_channel(channel, efx) {
efx_for_each_possible_channel_tx_queue(tx_queue, channel) {
if (tx_queue->initialised &&
tx_queue->flushed != FLUSH_DONE)
netif_err(efx, hw, efx->net_dev,
"tx queue %d flush command timed out\n",
tx_queue->queue);
tx_queue->flushed = FLUSH_DONE;
}
efx_for_each_channel_rx_queue(rx_queue, channel) {
if (rx_queue->flushed != FLUSH_DONE)
netif_err(efx, hw, efx->net_dev,
"rx queue %d flush command timed out\n",
efx_rx_queue_index(rx_queue));
rx_queue->flushed = FLUSH_DONE;
}
}
return -ETIMEDOUT;
efx_magic_event(efx_rx_queue_channel(rx_queue),
EFX_CHANNEL_MAGIC_FILL(rx_queue));
}
/**************************************************************************
......@@ -1315,18 +1367,10 @@ static inline void efx_nic_interrupts(struct efx_nic *efx,
void efx_nic_enable_interrupts(struct efx_nic *efx)
{
struct efx_channel *channel;
EFX_ZERO_OWORD(*((efx_oword_t *) efx->irq_status.addr));
wmb(); /* Ensure interrupt vector is clear before interrupts enabled */
/* Enable interrupts */
efx_nic_interrupts(efx, true, false);
/* Force processing of all the channels to get the EVQ RPTRs up to
date */
efx_for_each_channel(channel, efx)
efx_schedule_channel(channel);
}
void efx_nic_disable_interrupts(struct efx_nic *efx)
......@@ -1593,6 +1637,58 @@ void efx_nic_fini_interrupt(struct efx_nic *efx)
free_irq(efx->legacy_irq, efx);
}
/* Looks at available SRAM resources and works out how many queues we
* can support, and where things like descriptor caches should live.
*
* SRAM is split up as follows:
* 0 buftbl entries for channels
* efx->vf_buftbl_base buftbl entries for SR-IOV
* efx->rx_dc_base RX descriptor caches
* efx->tx_dc_base TX descriptor caches
*/
void efx_nic_dimension_resources(struct efx_nic *efx, unsigned sram_lim_qw)
{
unsigned vi_count, buftbl_min;
/* Account for the buffer table entries backing the datapath channels
* and the descriptor caches for those channels.
*/
buftbl_min = ((efx->n_rx_channels * EFX_MAX_DMAQ_SIZE +
efx->n_tx_channels * EFX_TXQ_TYPES * EFX_MAX_DMAQ_SIZE +
efx->n_channels * EFX_MAX_EVQ_SIZE)
* sizeof(efx_qword_t) / EFX_BUF_SIZE);
vi_count = max(efx->n_channels, efx->n_tx_channels * EFX_TXQ_TYPES);
#ifdef CONFIG_SFC_SRIOV
if (efx_sriov_wanted(efx)) {
unsigned vi_dc_entries, buftbl_free, entries_per_vf, vf_limit;
efx->vf_buftbl_base = buftbl_min;
vi_dc_entries = RX_DC_ENTRIES + TX_DC_ENTRIES;
vi_count = max(vi_count, EFX_VI_BASE);
buftbl_free = (sram_lim_qw - buftbl_min -
vi_count * vi_dc_entries);
entries_per_vf = ((vi_dc_entries + EFX_VF_BUFTBL_PER_VI) *
efx_vf_size(efx));
vf_limit = min(buftbl_free / entries_per_vf,
(1024U - EFX_VI_BASE) >> efx->vi_scale);
if (efx->vf_count > vf_limit) {
netif_err(efx, probe, efx->net_dev,
"Reducing VF count from from %d to %d\n",
efx->vf_count, vf_limit);
efx->vf_count = vf_limit;
}
vi_count += efx->vf_count * efx_vf_size(efx);
}
#endif
efx->tx_dc_base = sram_lim_qw - vi_count * TX_DC_ENTRIES;
efx->rx_dc_base = efx->tx_dc_base - vi_count * RX_DC_ENTRIES;
}
u32 efx_nic_fpga_ver(struct efx_nic *efx)
{
efx_oword_t altera_build;
......@@ -1605,11 +1701,9 @@ void efx_nic_init_common(struct efx_nic *efx)
efx_oword_t temp;
/* Set positions of descriptor caches in SRAM. */
EFX_POPULATE_OWORD_1(temp, FRF_AZ_SRM_TX_DC_BASE_ADR,
efx->type->tx_dc_base / 8);
EFX_POPULATE_OWORD_1(temp, FRF_AZ_SRM_TX_DC_BASE_ADR, efx->tx_dc_base);
efx_writeo(efx, &temp, FR_AZ_SRM_TX_DC_CFG);
EFX_POPULATE_OWORD_1(temp, FRF_AZ_SRM_RX_DC_BASE_ADR,
efx->type->rx_dc_base / 8);
EFX_POPULATE_OWORD_1(temp, FRF_AZ_SRM_RX_DC_BASE_ADR, efx->rx_dc_base);
efx_writeo(efx, &temp, FR_AZ_SRM_RX_DC_CFG);
/* Set TX descriptor cache size. */
......
......@@ -65,6 +65,11 @@ enum {
#define FALCON_GMAC_LOOPBACKS \
(1 << LOOPBACK_GMAC)
/* Alignment of PCIe DMA boundaries (4KB) */
#define EFX_PAGE_SIZE 4096
/* Size and alignment of buffer table entries (same) */
#define EFX_BUF_SIZE EFX_PAGE_SIZE
/**
* struct falcon_board_type - board operations and type information
* @id: Board type id, as found in NVRAM
......@@ -164,6 +169,95 @@ static inline struct efx_mcdi_mon *efx_mcdi_mon(struct efx_nic *efx)
}
#endif
/*
* On the SFC9000 family each port is associated with 1 PCI physical
* function (PF) handled by sfc and a configurable number of virtual
* functions (VFs) that may be handled by some other driver, often in
* a VM guest. The queue pointer registers are mapped in both PF and
* VF BARs such that an 8K region provides access to a single RX, TX
* and event queue (collectively a Virtual Interface, VI or VNIC).
*
* The PF has access to all 1024 VIs while VFs are mapped to VIs
* according to VI_BASE and VI_SCALE: VF i has access to VIs numbered
* in range [VI_BASE + i << VI_SCALE, VI_BASE + i + 1 << VI_SCALE).
* The number of VIs and the VI_SCALE value are configurable but must
* be established at boot time by firmware.
*/
/* Maximum VI_SCALE parameter supported by Siena */
#define EFX_VI_SCALE_MAX 6
/* Base VI to use for SR-IOV. Must be aligned to (1 << EFX_VI_SCALE_MAX),
* so this is the smallest allowed value. */
#define EFX_VI_BASE 128U
/* Maximum number of VFs allowed */
#define EFX_VF_COUNT_MAX 127
/* Limit EVQs on VFs to be only 8k to reduce buffer table reservation */
#define EFX_MAX_VF_EVQ_SIZE 8192UL
/* The number of buffer table entries reserved for each VI on a VF */
#define EFX_VF_BUFTBL_PER_VI \
((EFX_MAX_VF_EVQ_SIZE + 2 * EFX_MAX_DMAQ_SIZE) * \
sizeof(efx_qword_t) / EFX_BUF_SIZE)
#ifdef CONFIG_SFC_SRIOV
static inline bool efx_sriov_wanted(struct efx_nic *efx)
{
return efx->vf_count != 0;
}
static inline bool efx_sriov_enabled(struct efx_nic *efx)
{
return efx->vf_init_count != 0;
}
static inline unsigned int efx_vf_size(struct efx_nic *efx)
{
return 1 << efx->vi_scale;
}
extern int efx_init_sriov(void);
extern void efx_sriov_probe(struct efx_nic *efx);
extern int efx_sriov_init(struct efx_nic *efx);
extern void efx_sriov_mac_address_changed(struct efx_nic *efx);
extern void efx_sriov_tx_flush_done(struct efx_nic *efx, efx_qword_t *event);
extern void efx_sriov_rx_flush_done(struct efx_nic *efx, efx_qword_t *event);
extern void efx_sriov_event(struct efx_channel *channel, efx_qword_t *event);
extern void efx_sriov_desc_fetch_err(struct efx_nic *efx, unsigned dmaq);
extern void efx_sriov_flr(struct efx_nic *efx, unsigned flr);
extern void efx_sriov_reset(struct efx_nic *efx);
extern void efx_sriov_fini(struct efx_nic *efx);
extern void efx_fini_sriov(void);
#else
static inline bool efx_sriov_wanted(struct efx_nic *efx) { return false; }
static inline bool efx_sriov_enabled(struct efx_nic *efx) { return false; }
static inline unsigned int efx_vf_size(struct efx_nic *efx) { return 0; }
static inline int efx_init_sriov(void) { return 0; }
static inline void efx_sriov_probe(struct efx_nic *efx) {}
static inline int efx_sriov_init(struct efx_nic *efx) { return -EOPNOTSUPP; }
static inline void efx_sriov_mac_address_changed(struct efx_nic *efx) {}
static inline void efx_sriov_tx_flush_done(struct efx_nic *efx,
efx_qword_t *event) {}
static inline void efx_sriov_rx_flush_done(struct efx_nic *efx,
efx_qword_t *event) {}
static inline void efx_sriov_event(struct efx_channel *channel,
efx_qword_t *event) {}
static inline void efx_sriov_desc_fetch_err(struct efx_nic *efx, unsigned dmaq) {}
static inline void efx_sriov_flr(struct efx_nic *efx, unsigned flr) {}
static inline void efx_sriov_reset(struct efx_nic *efx) {}
static inline void efx_sriov_fini(struct efx_nic *efx) {}
static inline void efx_fini_sriov(void) {}
#endif
extern int efx_sriov_set_vf_mac(struct net_device *dev, int vf, u8 *mac);
extern int efx_sriov_set_vf_vlan(struct net_device *dev, int vf,
u16 vlan, u8 qos);
extern int efx_sriov_get_vf_config(struct net_device *dev, int vf,
struct ifla_vf_info *ivf);
extern int efx_sriov_set_vf_spoofchk(struct net_device *net_dev, int vf,
bool spoofchk);
extern const struct efx_nic_type falcon_a1_nic_type;
extern const struct efx_nic_type falcon_b0_nic_type;
extern const struct efx_nic_type siena_a0_nic_type;
......@@ -190,6 +284,7 @@ extern void efx_nic_init_rx(struct efx_rx_queue *rx_queue);
extern void efx_nic_fini_rx(struct efx_rx_queue *rx_queue);
extern void efx_nic_remove_rx(struct efx_rx_queue *rx_queue);
extern void efx_nic_notify_rx_desc(struct efx_rx_queue *rx_queue);
extern void efx_nic_generate_fill_event(struct efx_rx_queue *rx_queue);
/* Event data path */
extern int efx_nic_probe_eventq(struct efx_channel *channel);
......@@ -211,7 +306,6 @@ extern void falcon_update_stats_xmac(struct efx_nic *efx);
extern int efx_nic_init_interrupt(struct efx_nic *efx);
extern void efx_nic_enable_interrupts(struct efx_nic *efx);
extern void efx_nic_generate_test_event(struct efx_channel *channel);
extern void efx_nic_generate_fill_event(struct efx_channel *channel);
extern void efx_nic_generate_interrupt(struct efx_nic *efx);
extern void efx_nic_disable_interrupts(struct efx_nic *efx);
extern void efx_nic_fini_interrupt(struct efx_nic *efx);
......@@ -225,6 +319,8 @@ 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);
extern int falcon_reset_xaui(struct efx_nic *efx);
extern void
efx_nic_dimension_resources(struct efx_nic *efx, unsigned sram_lim_qw);
extern void efx_nic_init_common(struct efx_nic *efx);
extern void efx_nic_push_rx_indir_table(struct efx_nic *efx);
......@@ -278,8 +374,8 @@ extern void efx_nic_get_regs(struct efx_nic *efx, void *buf);
#define MAC_DATA_LBN 0
#define MAC_DATA_WIDTH 32
extern void efx_nic_generate_event(struct efx_channel *channel,
efx_qword_t *event);
extern void efx_generate_event(struct efx_nic *efx, unsigned int evq,
efx_qword_t *event);
extern void falcon_poll_xmac(struct efx_nic *efx);
......
......@@ -2446,8 +2446,8 @@
#define FRF_CZ_RMFT_RXQ_ID_WIDTH 12
#define FRF_CZ_RMFT_WILDCARD_MATCH_LBN 60
#define FRF_CZ_RMFT_WILDCARD_MATCH_WIDTH 1
#define FRF_CZ_RMFT_DEST_MAC_LBN 16
#define FRF_CZ_RMFT_DEST_MAC_WIDTH 44
#define FRF_CZ_RMFT_DEST_MAC_LBN 12
#define FRF_CZ_RMFT_DEST_MAC_WIDTH 48
#define FRF_CZ_RMFT_VLAN_ID_LBN 0
#define FRF_CZ_RMFT_VLAN_ID_WIDTH 12
......@@ -2523,8 +2523,8 @@
#define FRF_CZ_TMFT_TXQ_ID_WIDTH 12
#define FRF_CZ_TMFT_WILDCARD_MATCH_LBN 60
#define FRF_CZ_TMFT_WILDCARD_MATCH_WIDTH 1
#define FRF_CZ_TMFT_SRC_MAC_LBN 16
#define FRF_CZ_TMFT_SRC_MAC_WIDTH 44
#define FRF_CZ_TMFT_SRC_MAC_LBN 12
#define FRF_CZ_TMFT_SRC_MAC_WIDTH 48
#define FRF_CZ_TMFT_VLAN_ID_LBN 0
#define FRF_CZ_TMFT_VLAN_ID_WIDTH 12
......@@ -2895,17 +2895,17 @@
/* RX_MAC_FILTER_TBL0 */
/* RMFT_DEST_MAC is wider than 32 bits */
#define FRF_CZ_RMFT_DEST_MAC_LO_LBN 12
#define FRF_CZ_RMFT_DEST_MAC_LO_LBN FRF_CZ_RMFT_DEST_MAC_LBN
#define FRF_CZ_RMFT_DEST_MAC_LO_WIDTH 32
#define FRF_CZ_RMFT_DEST_MAC_HI_LBN 44
#define FRF_CZ_RMFT_DEST_MAC_HI_WIDTH 16
#define FRF_CZ_RMFT_DEST_MAC_HI_LBN (FRF_CZ_RMFT_DEST_MAC_LBN + 32)
#define FRF_CZ_RMFT_DEST_MAC_HI_WIDTH (FRF_CZ_RMFT_DEST_MAC_WIDTH - 32)
/* TX_MAC_FILTER_TBL0 */
/* TMFT_SRC_MAC is wider than 32 bits */
#define FRF_CZ_TMFT_SRC_MAC_LO_LBN 12
#define FRF_CZ_TMFT_SRC_MAC_LO_LBN FRF_CZ_TMFT_SRC_MAC_LBN
#define FRF_CZ_TMFT_SRC_MAC_LO_WIDTH 32
#define FRF_CZ_TMFT_SRC_MAC_HI_LBN 44
#define FRF_CZ_TMFT_SRC_MAC_HI_WIDTH 16
#define FRF_CZ_TMFT_SRC_MAC_HI_LBN (FRF_CZ_TMFT_SRC_MAC_LBN + 32)
#define FRF_CZ_TMFT_SRC_MAC_HI_WIDTH (FRF_CZ_TMFT_SRC_MAC_WIDTH - 32)
/* TX_PACE_TBL */
/* Values >20 are documented as reserved, but will result in a queue going
......
......@@ -405,10 +405,9 @@ void efx_fast_push_rx_descriptors(struct efx_rx_queue *rx_queue)
void efx_rx_slow_fill(unsigned long context)
{
struct efx_rx_queue *rx_queue = (struct efx_rx_queue *)context;
struct efx_channel *channel = efx_rx_queue_channel(rx_queue);
/* Post an event to cause NAPI to run and refill the queue */
efx_nic_generate_fill_event(channel);
efx_nic_generate_fill_event(rx_queue);
++rx_queue->slow_fill_count;
}
......@@ -706,6 +705,7 @@ void efx_init_rx_queue(struct efx_rx_queue *rx_queue)
rx_queue->fast_fill_limit = limit;
/* Set up RX descriptor ring */
rx_queue->enabled = true;
efx_nic_init_rx(rx_queue);
}
......@@ -717,6 +717,9 @@ void efx_fini_rx_queue(struct efx_rx_queue *rx_queue)
netif_dbg(rx_queue->efx, drv, rx_queue->efx->net_dev,
"shutting down RX queue %d\n", efx_rx_queue_index(rx_queue));
/* A flush failure might have left rx_queue->enabled */
rx_queue->enabled = false;
del_timer_sync(&rx_queue->slow_fill);
efx_nic_fini_rx(rx_queue);
......
......@@ -225,6 +225,15 @@ static int siena_probe_nvconfig(struct efx_nic *efx)
return rc;
}
static void siena_dimension_resources(struct efx_nic *efx)
{
/* Each port has a small block of internal SRAM dedicated to
* the buffer table and descriptor caches. In theory we can
* map both blocks to one port, but we don't.
*/
efx_nic_dimension_resources(efx, FR_CZ_BUF_FULL_TBL_ROWS / 2);
}
static int siena_probe_nic(struct efx_nic *efx)
{
struct siena_nic_data *nic_data;
......@@ -304,6 +313,8 @@ static int siena_probe_nic(struct efx_nic *efx)
if (rc)
goto fail5;
efx_sriov_probe(efx);
return 0;
fail5:
......@@ -619,6 +630,7 @@ const struct efx_nic_type siena_a0_nic_type = {
.probe = siena_probe_nic,
.remove = siena_remove_nic,
.init = siena_init_nic,
.dimension_resources = siena_dimension_resources,
.fini = efx_port_dummy_op_void,
.monitor = NULL,
.map_reset_reason = siena_map_reset_reason,
......@@ -657,8 +669,6 @@ const struct efx_nic_type siena_a0_nic_type = {
* interrupt handler only supports 32
* channels */
.timer_period_max = 1 << FRF_CZ_TC_TIMER_VAL_WIDTH,
.tx_dc_base = 0x88000,
.rx_dc_base = 0x68000,
.offload_features = (NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM |
NETIF_F_RXHASH | NETIF_F_NTUPLE),
};
/****************************************************************************
* Driver for Solarflare Solarstorm network controllers and boards
* Copyright 2010-2011 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 <linux/pci.h>
#include <linux/module.h>
#include "net_driver.h"
#include "efx.h"
#include "nic.h"
#include "io.h"
#include "mcdi.h"
#include "filter.h"
#include "mcdi_pcol.h"
#include "regs.h"
#include "vfdi.h"
/* Number of longs required to track all the VIs in a VF */
#define VI_MASK_LENGTH BITS_TO_LONGS(1 << EFX_VI_SCALE_MAX)
/**
* enum efx_vf_tx_filter_mode - TX MAC filtering behaviour
* @VF_TX_FILTER_OFF: Disabled
* @VF_TX_FILTER_AUTO: Enabled if MAC address assigned to VF and only
* 2 TX queues allowed per VF.
* @VF_TX_FILTER_ON: Enabled
*/
enum efx_vf_tx_filter_mode {
VF_TX_FILTER_OFF,
VF_TX_FILTER_AUTO,
VF_TX_FILTER_ON,
};
/**
* struct efx_vf - Back-end resource and protocol state for a PCI VF
* @efx: The Efx NIC owning this VF
* @pci_rid: The PCI requester ID for this VF
* @pci_name: The PCI name (formatted address) of this VF
* @index: Index of VF within its port and PF.
* @req: VFDI incoming request work item. Incoming USR_EV events are received
* by the NAPI handler, but must be handled by executing MCDI requests
* inside a work item.
* @req_addr: VFDI incoming request DMA address (in VF's PCI address space).
* @req_type: Expected next incoming (from VF) %VFDI_EV_TYPE member.
* @req_seqno: Expected next incoming (from VF) %VFDI_EV_SEQ member.
* @msg_seqno: Next %VFDI_EV_SEQ member to reply to VF. Protected by
* @status_lock
* @busy: VFDI request queued to be processed or being processed. Receiving
* a VFDI request when @busy is set is an error condition.
* @buf: Incoming VFDI requests are DMA from the VF into this buffer.
* @buftbl_base: Buffer table entries for this VF start at this index.
* @rx_filtering: Receive filtering has been requested by the VF driver.
* @rx_filter_flags: The flags sent in the %VFDI_OP_INSERT_FILTER request.
* @rx_filter_qid: VF relative qid for RX filter requested by VF.
* @rx_filter_id: Receive MAC filter ID. Only one filter per VF is supported.
* @tx_filter_mode: Transmit MAC filtering mode.
* @tx_filter_id: Transmit MAC filter ID.
* @addr: The MAC address and outer vlan tag of the VF.
* @status_addr: VF DMA address of page for &struct vfdi_status updates.
* @status_lock: Mutex protecting @msg_seqno, @status_addr, @addr,
* @peer_page_addrs and @peer_page_count from simultaneous
* updates by the VM and consumption by
* efx_sriov_update_vf_addr()
* @peer_page_addrs: Pointer to an array of guest pages for local addresses.
* @peer_page_count: Number of entries in @peer_page_count.
* @evq0_addrs: Array of guest pages backing evq0.
* @evq0_count: Number of entries in @evq0_addrs.
* @flush_waitq: wait queue used by %VFDI_OP_FINI_ALL_QUEUES handler
* to wait for flush completions.
* @txq_lock: Mutex for TX queue allocation.
* @txq_mask: Mask of initialized transmit queues.
* @txq_count: Number of initialized transmit queues.
* @rxq_mask: Mask of initialized receive queues.
* @rxq_count: Number of initialized receive queues.
* @rxq_retry_mask: Mask or receive queues that need to be flushed again
* due to flush failure.
* @rxq_retry_count: Number of receive queues in @rxq_retry_mask.
* @reset_work: Work item to schedule a VF reset.
*/
struct efx_vf {
struct efx_nic *efx;
unsigned int pci_rid;
char pci_name[13]; /* dddd:bb:dd.f */
unsigned int index;
struct work_struct req;
u64 req_addr;
int req_type;
unsigned req_seqno;
unsigned msg_seqno;
bool busy;
struct efx_buffer buf;
unsigned buftbl_base;
bool rx_filtering;
enum efx_filter_flags rx_filter_flags;
unsigned rx_filter_qid;
int rx_filter_id;
enum efx_vf_tx_filter_mode tx_filter_mode;
int tx_filter_id;
struct vfdi_endpoint addr;
u64 status_addr;
struct mutex status_lock;
u64 *peer_page_addrs;
unsigned peer_page_count;
u64 evq0_addrs[EFX_MAX_VF_EVQ_SIZE * sizeof(efx_qword_t) /
EFX_BUF_SIZE];
unsigned evq0_count;
wait_queue_head_t flush_waitq;
struct mutex txq_lock;
unsigned long txq_mask[VI_MASK_LENGTH];
unsigned txq_count;
unsigned long rxq_mask[VI_MASK_LENGTH];
unsigned rxq_count;
unsigned long rxq_retry_mask[VI_MASK_LENGTH];
atomic_t rxq_retry_count;
struct work_struct reset_work;
};
struct efx_memcpy_req {
unsigned int from_rid;
void *from_buf;
u64 from_addr;
unsigned int to_rid;
u64 to_addr;
unsigned length;
};
/**
* struct efx_local_addr - A MAC address on the vswitch without a VF.
*
* Siena does not have a switch, so VFs can't transmit data to each
* other. Instead the VFs must be made aware of the local addresses
* on the vswitch, so that they can arrange for an alternative
* software datapath to be used.
*
* @link: List head for insertion into efx->local_addr_list.
* @addr: Ethernet address
*/
struct efx_local_addr {
struct list_head link;
u8 addr[ETH_ALEN];
};
/**
* struct efx_endpoint_page - Page of vfdi_endpoint structures
*
* @link: List head for insertion into efx->local_page_list.
* @ptr: Pointer to page.
* @addr: DMA address of page.
*/
struct efx_endpoint_page {
struct list_head link;
void *ptr;
dma_addr_t addr;
};
/* Buffer table entries are reserved txq0,rxq0,evq0,txq1,rxq1,evq1 */
#define EFX_BUFTBL_TXQ_BASE(_vf, _qid) \
((_vf)->buftbl_base + EFX_VF_BUFTBL_PER_VI * (_qid))
#define EFX_BUFTBL_RXQ_BASE(_vf, _qid) \
(EFX_BUFTBL_TXQ_BASE(_vf, _qid) + \
(EFX_MAX_DMAQ_SIZE * sizeof(efx_qword_t) / EFX_BUF_SIZE))
#define EFX_BUFTBL_EVQ_BASE(_vf, _qid) \
(EFX_BUFTBL_TXQ_BASE(_vf, _qid) + \
(2 * EFX_MAX_DMAQ_SIZE * sizeof(efx_qword_t) / EFX_BUF_SIZE))
#define EFX_FIELD_MASK(_field) \
((1 << _field ## _WIDTH) - 1)
/* VFs can only use this many transmit channels */
static unsigned int vf_max_tx_channels = 2;
module_param(vf_max_tx_channels, uint, 0444);
MODULE_PARM_DESC(vf_max_tx_channels,
"Limit the number of TX channels VFs can use");
static int max_vfs = -1;
module_param(max_vfs, int, 0444);
MODULE_PARM_DESC(max_vfs,
"Reduce the number of VFs initialized by the driver");
/* Workqueue used by VFDI communication. We can't use the global
* workqueue because it may be running the VF driver's probe()
* routine, which will be blocked there waiting for a VFDI response.
*/
static struct workqueue_struct *vfdi_workqueue;
static unsigned abs_index(struct efx_vf *vf, unsigned index)
{
return EFX_VI_BASE + vf->index * efx_vf_size(vf->efx) + index;
}
static int efx_sriov_cmd(struct efx_nic *efx, bool enable,
unsigned *vi_scale_out, unsigned *vf_total_out)
{
u8 inbuf[MC_CMD_SRIOV_IN_LEN];
u8 outbuf[MC_CMD_SRIOV_OUT_LEN];
unsigned vi_scale, vf_total;
size_t outlen;
int rc;
MCDI_SET_DWORD(inbuf, SRIOV_IN_ENABLE, enable ? 1 : 0);
MCDI_SET_DWORD(inbuf, SRIOV_IN_VI_BASE, EFX_VI_BASE);
MCDI_SET_DWORD(inbuf, SRIOV_IN_VF_COUNT, efx->vf_count);
rc = efx_mcdi_rpc(efx, MC_CMD_SRIOV, inbuf, MC_CMD_SRIOV_IN_LEN,
outbuf, MC_CMD_SRIOV_OUT_LEN, &outlen);
if (rc)
return rc;
if (outlen < MC_CMD_SRIOV_OUT_LEN)
return -EIO;
vf_total = MCDI_DWORD(outbuf, SRIOV_OUT_VF_TOTAL);
vi_scale = MCDI_DWORD(outbuf, SRIOV_OUT_VI_SCALE);
if (vi_scale > EFX_VI_SCALE_MAX)
return -EOPNOTSUPP;
if (vi_scale_out)
*vi_scale_out = vi_scale;
if (vf_total_out)
*vf_total_out = vf_total;
return 0;
}
static void efx_sriov_usrev(struct efx_nic *efx, bool enabled)
{
efx_oword_t reg;
EFX_POPULATE_OWORD_2(reg,
FRF_CZ_USREV_DIS, enabled ? 0 : 1,
FRF_CZ_DFLT_EVQ, efx->vfdi_channel->channel);
efx_writeo(efx, &reg, FR_CZ_USR_EV_CFG);
}
static int efx_sriov_memcpy(struct efx_nic *efx, struct efx_memcpy_req *req,
unsigned int count)
{
u8 *inbuf, *record;
unsigned int used;
u32 from_rid, from_hi, from_lo;
int rc;
mb(); /* Finish writing source/reading dest before DMA starts */
used = MC_CMD_MEMCPY_IN_LEN(count);
if (WARN_ON(used > MCDI_CTL_SDU_LEN_MAX))
return -ENOBUFS;
/* Allocate room for the largest request */
inbuf = kzalloc(MCDI_CTL_SDU_LEN_MAX, GFP_KERNEL);
if (inbuf == NULL)
return -ENOMEM;
record = inbuf;
MCDI_SET_DWORD(record, MEMCPY_IN_RECORD, count);
while (count-- > 0) {
MCDI_SET_DWORD(record, MEMCPY_RECORD_TYPEDEF_TO_RID,
req->to_rid);
MCDI_SET_DWORD(record, MEMCPY_RECORD_TYPEDEF_TO_ADDR_LO,
(u32)req->to_addr);
MCDI_SET_DWORD(record, MEMCPY_RECORD_TYPEDEF_TO_ADDR_HI,
(u32)(req->to_addr >> 32));
if (req->from_buf == NULL) {
from_rid = req->from_rid;
from_lo = (u32)req->from_addr;
from_hi = (u32)(req->from_addr >> 32);
} else {
if (WARN_ON(used + req->length > MCDI_CTL_SDU_LEN_MAX)) {
rc = -ENOBUFS;
goto out;
}
from_rid = MC_CMD_MEMCPY_RECORD_TYPEDEF_RID_INLINE;
from_lo = used;
from_hi = 0;
memcpy(inbuf + used, req->from_buf, req->length);
used += req->length;
}
MCDI_SET_DWORD(record, MEMCPY_RECORD_TYPEDEF_FROM_RID, from_rid);
MCDI_SET_DWORD(record, MEMCPY_RECORD_TYPEDEF_FROM_ADDR_LO,
from_lo);
MCDI_SET_DWORD(record, MEMCPY_RECORD_TYPEDEF_FROM_ADDR_HI,
from_hi);
MCDI_SET_DWORD(record, MEMCPY_RECORD_TYPEDEF_LENGTH,
req->length);
++req;
record += MC_CMD_MEMCPY_IN_RECORD_LEN;
}
rc = efx_mcdi_rpc(efx, MC_CMD_MEMCPY, inbuf, used, NULL, 0, NULL);
out:
kfree(inbuf);
mb(); /* Don't write source/read dest before DMA is complete */
return rc;
}
/* The TX filter is entirely controlled by this driver, and is modified
* underneath the feet of the VF
*/
static void efx_sriov_reset_tx_filter(struct efx_vf *vf)
{
struct efx_nic *efx = vf->efx;
struct efx_filter_spec filter;
u16 vlan;
int rc;
if (vf->tx_filter_id != -1) {
efx_filter_remove_id_safe(efx, EFX_FILTER_PRI_REQUIRED,
vf->tx_filter_id);
netif_dbg(efx, hw, efx->net_dev, "Removed vf %s tx filter %d\n",
vf->pci_name, vf->tx_filter_id);
vf->tx_filter_id = -1;
}
if (is_zero_ether_addr(vf->addr.mac_addr))
return;
/* Turn on TX filtering automatically if not explicitly
* enabled or disabled.
*/
if (vf->tx_filter_mode == VF_TX_FILTER_AUTO && vf_max_tx_channels <= 2)
vf->tx_filter_mode = VF_TX_FILTER_ON;
vlan = ntohs(vf->addr.tci) & VLAN_VID_MASK;
efx_filter_init_tx(&filter, abs_index(vf, 0));
rc = efx_filter_set_eth_local(&filter,
vlan ? vlan : EFX_FILTER_VID_UNSPEC,
vf->addr.mac_addr);
BUG_ON(rc);
rc = efx_filter_insert_filter(efx, &filter, true);
if (rc < 0) {
netif_warn(efx, hw, efx->net_dev,
"Unable to migrate tx filter for vf %s\n",
vf->pci_name);
} else {
netif_dbg(efx, hw, efx->net_dev, "Inserted vf %s tx filter %d\n",
vf->pci_name, rc);
vf->tx_filter_id = rc;
}
}
/* The RX filter is managed here on behalf of the VF driver */
static void efx_sriov_reset_rx_filter(struct efx_vf *vf)
{
struct efx_nic *efx = vf->efx;
struct efx_filter_spec filter;
u16 vlan;
int rc;
if (vf->rx_filter_id != -1) {
efx_filter_remove_id_safe(efx, EFX_FILTER_PRI_REQUIRED,
vf->rx_filter_id);
netif_dbg(efx, hw, efx->net_dev, "Removed vf %s rx filter %d\n",
vf->pci_name, vf->rx_filter_id);
vf->rx_filter_id = -1;
}
if (!vf->rx_filtering || is_zero_ether_addr(vf->addr.mac_addr))
return;
vlan = ntohs(vf->addr.tci) & VLAN_VID_MASK;
efx_filter_init_rx(&filter, EFX_FILTER_PRI_REQUIRED,
vf->rx_filter_flags,
abs_index(vf, vf->rx_filter_qid));
rc = efx_filter_set_eth_local(&filter,
vlan ? vlan : EFX_FILTER_VID_UNSPEC,
vf->addr.mac_addr);
BUG_ON(rc);
rc = efx_filter_insert_filter(efx, &filter, true);
if (rc < 0) {
netif_warn(efx, hw, efx->net_dev,
"Unable to insert rx filter for vf %s\n",
vf->pci_name);
} else {
netif_dbg(efx, hw, efx->net_dev, "Inserted vf %s rx filter %d\n",
vf->pci_name, rc);
vf->rx_filter_id = rc;
}
}
static void __efx_sriov_update_vf_addr(struct efx_vf *vf)
{
efx_sriov_reset_tx_filter(vf);
efx_sriov_reset_rx_filter(vf);
queue_work(vfdi_workqueue, &vf->efx->peer_work);
}
/* Push the peer list to this VF. The caller must hold status_lock to interlock
* with VFDI requests, and they must be serialised against manipulation of
* local_page_list, either by acquiring local_lock or by running from
* efx_sriov_peer_work()
*/
static void __efx_sriov_push_vf_status(struct efx_vf *vf)
{
struct efx_nic *efx = vf->efx;
struct vfdi_status *status = efx->vfdi_status.addr;
struct efx_memcpy_req copy[4];
struct efx_endpoint_page *epp;
unsigned int pos, count;
unsigned data_offset;
efx_qword_t event;
WARN_ON(!mutex_is_locked(&vf->status_lock));
WARN_ON(!vf->status_addr);
status->local = vf->addr;
status->generation_end = ++status->generation_start;
memset(copy, '\0', sizeof(copy));
/* Write generation_start */
copy[0].from_buf = &status->generation_start;
copy[0].to_rid = vf->pci_rid;
copy[0].to_addr = vf->status_addr + offsetof(struct vfdi_status,
generation_start);
copy[0].length = sizeof(status->generation_start);
/* DMA the rest of the structure (excluding the generations). This
* assumes that the non-generation portion of vfdi_status is in
* one chunk starting at the version member.
*/
data_offset = offsetof(struct vfdi_status, version);
copy[1].from_rid = efx->pci_dev->devfn;
copy[1].from_addr = efx->vfdi_status.dma_addr + data_offset;
copy[1].to_rid = vf->pci_rid;
copy[1].to_addr = vf->status_addr + data_offset;
copy[1].length = status->length - data_offset;
/* Copy the peer pages */
pos = 2;
count = 0;
list_for_each_entry(epp, &efx->local_page_list, link) {
if (count == vf->peer_page_count) {
/* The VF driver will know they need to provide more
* pages because peer_addr_count is too large.
*/
break;
}
copy[pos].from_buf = NULL;
copy[pos].from_rid = efx->pci_dev->devfn;
copy[pos].from_addr = epp->addr;
copy[pos].to_rid = vf->pci_rid;
copy[pos].to_addr = vf->peer_page_addrs[count];
copy[pos].length = EFX_PAGE_SIZE;
if (++pos == ARRAY_SIZE(copy)) {
efx_sriov_memcpy(efx, copy, ARRAY_SIZE(copy));
pos = 0;
}
++count;
}
/* Write generation_end */
copy[pos].from_buf = &status->generation_end;
copy[pos].to_rid = vf->pci_rid;
copy[pos].to_addr = vf->status_addr + offsetof(struct vfdi_status,
generation_end);
copy[pos].length = sizeof(status->generation_end);
efx_sriov_memcpy(efx, copy, pos + 1);
/* Notify the guest */
EFX_POPULATE_QWORD_3(event,
FSF_AZ_EV_CODE, FSE_CZ_EV_CODE_USER_EV,
VFDI_EV_SEQ, (vf->msg_seqno & 0xff),
VFDI_EV_TYPE, VFDI_EV_TYPE_STATUS);
++vf->msg_seqno;
efx_generate_event(efx, EFX_VI_BASE + vf->index * efx_vf_size(efx),
&event);
}
static void efx_sriov_bufs(struct efx_nic *efx, unsigned offset,
u64 *addr, unsigned count)
{
efx_qword_t buf;
unsigned pos;
for (pos = 0; pos < count; ++pos) {
EFX_POPULATE_QWORD_3(buf,
FRF_AZ_BUF_ADR_REGION, 0,
FRF_AZ_BUF_ADR_FBUF,
addr ? addr[pos] >> 12 : 0,
FRF_AZ_BUF_OWNER_ID_FBUF, 0);
efx_sram_writeq(efx, efx->membase + FR_BZ_BUF_FULL_TBL,
&buf, offset + pos);
}
}
static bool bad_vf_index(struct efx_nic *efx, unsigned index)
{
return index >= efx_vf_size(efx);
}
static bool bad_buf_count(unsigned buf_count, unsigned max_entry_count)
{
unsigned max_buf_count = max_entry_count *
sizeof(efx_qword_t) / EFX_BUF_SIZE;
return ((buf_count & (buf_count - 1)) || buf_count > max_buf_count);
}
/* Check that VI specified by per-port index belongs to a VF.
* Optionally set VF index and VI index within the VF.
*/
static bool map_vi_index(struct efx_nic *efx, unsigned abs_index,
struct efx_vf **vf_out, unsigned *rel_index_out)
{
unsigned vf_i;
if (abs_index < EFX_VI_BASE)
return true;
vf_i = (abs_index - EFX_VI_BASE) * efx_vf_size(efx);
if (vf_i >= efx->vf_init_count)
return true;
if (vf_out)
*vf_out = efx->vf + vf_i;
if (rel_index_out)
*rel_index_out = abs_index % efx_vf_size(efx);
return false;
}
static int efx_vfdi_init_evq(struct efx_vf *vf)
{
struct efx_nic *efx = vf->efx;
struct vfdi_req *req = vf->buf.addr;
unsigned vf_evq = req->u.init_evq.index;
unsigned buf_count = req->u.init_evq.buf_count;
unsigned abs_evq = abs_index(vf, vf_evq);
unsigned buftbl = EFX_BUFTBL_EVQ_BASE(vf, vf_evq);
efx_oword_t reg;
if (bad_vf_index(efx, vf_evq) ||
bad_buf_count(buf_count, EFX_MAX_VF_EVQ_SIZE)) {
if (net_ratelimit())
netif_err(efx, hw, efx->net_dev,
"ERROR: Invalid INIT_EVQ from %s: evq %d bufs %d\n",
vf->pci_name, vf_evq, buf_count);
return VFDI_RC_EINVAL;
}
efx_sriov_bufs(efx, buftbl, req->u.init_evq.addr, buf_count);
EFX_POPULATE_OWORD_3(reg,
FRF_CZ_TIMER_Q_EN, 1,
FRF_CZ_HOST_NOTIFY_MODE, 0,
FRF_CZ_TIMER_MODE, FFE_CZ_TIMER_MODE_DIS);
efx_writeo_table(efx, &reg, FR_BZ_TIMER_TBL, abs_evq);
EFX_POPULATE_OWORD_3(reg,
FRF_AZ_EVQ_EN, 1,
FRF_AZ_EVQ_SIZE, __ffs(buf_count),
FRF_AZ_EVQ_BUF_BASE_ID, buftbl);
efx_writeo_table(efx, &reg, FR_BZ_EVQ_PTR_TBL, abs_evq);
if (vf_evq == 0) {
memcpy(vf->evq0_addrs, req->u.init_evq.addr,
buf_count * sizeof(u64));
vf->evq0_count = buf_count;
}
return VFDI_RC_SUCCESS;
}
static int efx_vfdi_init_rxq(struct efx_vf *vf)
{
struct efx_nic *efx = vf->efx;
struct vfdi_req *req = vf->buf.addr;
unsigned vf_rxq = req->u.init_rxq.index;
unsigned vf_evq = req->u.init_rxq.evq;
unsigned buf_count = req->u.init_rxq.buf_count;
unsigned buftbl = EFX_BUFTBL_RXQ_BASE(vf, vf_rxq);
unsigned label;
efx_oword_t reg;
if (bad_vf_index(efx, vf_evq) || bad_vf_index(efx, vf_rxq) ||
bad_buf_count(buf_count, EFX_MAX_DMAQ_SIZE)) {
if (net_ratelimit())
netif_err(efx, hw, efx->net_dev,
"ERROR: Invalid INIT_RXQ from %s: rxq %d evq %d "
"buf_count %d\n", vf->pci_name, vf_rxq,
vf_evq, buf_count);
return VFDI_RC_EINVAL;
}
if (__test_and_set_bit(req->u.init_rxq.index, vf->rxq_mask))
++vf->rxq_count;
efx_sriov_bufs(efx, buftbl, req->u.init_rxq.addr, buf_count);
label = req->u.init_rxq.label & EFX_FIELD_MASK(FRF_AZ_RX_DESCQ_LABEL);
EFX_POPULATE_OWORD_6(reg,
FRF_AZ_RX_DESCQ_BUF_BASE_ID, buftbl,
FRF_AZ_RX_DESCQ_EVQ_ID, abs_index(vf, vf_evq),
FRF_AZ_RX_DESCQ_LABEL, label,
FRF_AZ_RX_DESCQ_SIZE, __ffs(buf_count),
FRF_AZ_RX_DESCQ_JUMBO,
!!(req->u.init_rxq.flags &
VFDI_RXQ_FLAG_SCATTER_EN),
FRF_AZ_RX_DESCQ_EN, 1);
efx_writeo_table(efx, &reg, FR_BZ_RX_DESC_PTR_TBL,
abs_index(vf, vf_rxq));
return VFDI_RC_SUCCESS;
}
static int efx_vfdi_init_txq(struct efx_vf *vf)
{
struct efx_nic *efx = vf->efx;
struct vfdi_req *req = vf->buf.addr;
unsigned vf_txq = req->u.init_txq.index;
unsigned vf_evq = req->u.init_txq.evq;
unsigned buf_count = req->u.init_txq.buf_count;
unsigned buftbl = EFX_BUFTBL_TXQ_BASE(vf, vf_txq);
unsigned label, eth_filt_en;
efx_oword_t reg;
if (bad_vf_index(efx, vf_evq) || bad_vf_index(efx, vf_txq) ||
vf_txq >= vf_max_tx_channels ||
bad_buf_count(buf_count, EFX_MAX_DMAQ_SIZE)) {
if (net_ratelimit())
netif_err(efx, hw, efx->net_dev,
"ERROR: Invalid INIT_TXQ from %s: txq %d evq %d "
"buf_count %d\n", vf->pci_name, vf_txq,
vf_evq, buf_count);
return VFDI_RC_EINVAL;
}
mutex_lock(&vf->txq_lock);
if (__test_and_set_bit(req->u.init_txq.index, vf->txq_mask))
++vf->txq_count;
mutex_unlock(&vf->txq_lock);
efx_sriov_bufs(efx, buftbl, req->u.init_txq.addr, buf_count);
eth_filt_en = vf->tx_filter_mode == VF_TX_FILTER_ON;
label = req->u.init_txq.label & EFX_FIELD_MASK(FRF_AZ_TX_DESCQ_LABEL);
EFX_POPULATE_OWORD_8(reg,
FRF_CZ_TX_DPT_Q_MASK_WIDTH, min(efx->vi_scale, 1U),
FRF_CZ_TX_DPT_ETH_FILT_EN, eth_filt_en,
FRF_AZ_TX_DESCQ_EN, 1,
FRF_AZ_TX_DESCQ_BUF_BASE_ID, buftbl,
FRF_AZ_TX_DESCQ_EVQ_ID, abs_index(vf, vf_evq),
FRF_AZ_TX_DESCQ_LABEL, label,
FRF_AZ_TX_DESCQ_SIZE, __ffs(buf_count),
FRF_BZ_TX_NON_IP_DROP_DIS, 1);
efx_writeo_table(efx, &reg, FR_BZ_TX_DESC_PTR_TBL,
abs_index(vf, vf_txq));
return VFDI_RC_SUCCESS;
}
/* Returns true when efx_vfdi_fini_all_queues should wake */
static bool efx_vfdi_flush_wake(struct efx_vf *vf)
{
/* Ensure that all updates are visible to efx_vfdi_fini_all_queues() */
smp_mb();
return (!vf->txq_count && !vf->rxq_count) ||
atomic_read(&vf->rxq_retry_count);
}
static void efx_vfdi_flush_clear(struct efx_vf *vf)
{
memset(vf->txq_mask, 0, sizeof(vf->txq_mask));
vf->txq_count = 0;
memset(vf->rxq_mask, 0, sizeof(vf->rxq_mask));
vf->rxq_count = 0;
memset(vf->rxq_retry_mask, 0, sizeof(vf->rxq_retry_mask));
atomic_set(&vf->rxq_retry_count, 0);
}
static int efx_vfdi_fini_all_queues(struct efx_vf *vf)
{
struct efx_nic *efx = vf->efx;
efx_oword_t reg;
unsigned count = efx_vf_size(efx);
unsigned vf_offset = EFX_VI_BASE + vf->index * efx_vf_size(efx);
unsigned timeout = HZ;
unsigned index, rxqs_count;
__le32 *rxqs;
int rc;
rxqs = kmalloc(count * sizeof(*rxqs), GFP_KERNEL);
if (rxqs == NULL)
return VFDI_RC_ENOMEM;
rtnl_lock();
if (efx->fc_disable++ == 0)
efx_mcdi_set_mac(efx);
rtnl_unlock();
/* Flush all the initialized queues */
rxqs_count = 0;
for (index = 0; index < count; ++index) {
if (test_bit(index, vf->txq_mask)) {
EFX_POPULATE_OWORD_2(reg,
FRF_AZ_TX_FLUSH_DESCQ_CMD, 1,
FRF_AZ_TX_FLUSH_DESCQ,
vf_offset + index);
efx_writeo(efx, &reg, FR_AZ_TX_FLUSH_DESCQ);
}
if (test_bit(index, vf->rxq_mask))
rxqs[rxqs_count++] = cpu_to_le32(vf_offset + index);
}
atomic_set(&vf->rxq_retry_count, 0);
while (timeout && (vf->rxq_count || vf->txq_count)) {
rc = efx_mcdi_rpc(efx, MC_CMD_FLUSH_RX_QUEUES, (u8 *)rxqs,
rxqs_count * sizeof(*rxqs), NULL, 0, NULL);
WARN_ON(rc < 0);
timeout = wait_event_timeout(vf->flush_waitq,
efx_vfdi_flush_wake(vf),
timeout);
rxqs_count = 0;
for (index = 0; index < count; ++index) {
if (test_and_clear_bit(index, vf->rxq_retry_mask)) {
atomic_dec(&vf->rxq_retry_count);
rxqs[rxqs_count++] =
cpu_to_le32(vf_offset + index);
}
}
}
rtnl_lock();
if (--efx->fc_disable == 0)
efx_mcdi_set_mac(efx);
rtnl_unlock();
/* Irrespective of success/failure, fini the queues */
EFX_ZERO_OWORD(reg);
for (index = 0; index < count; ++index) {
efx_writeo_table(efx, &reg, FR_BZ_RX_DESC_PTR_TBL,
vf_offset + index);
efx_writeo_table(efx, &reg, FR_BZ_TX_DESC_PTR_TBL,
vf_offset + index);
efx_writeo_table(efx, &reg, FR_BZ_EVQ_PTR_TBL,
vf_offset + index);
efx_writeo_table(efx, &reg, FR_BZ_TIMER_TBL,
vf_offset + index);
}
efx_sriov_bufs(efx, vf->buftbl_base, NULL,
EFX_VF_BUFTBL_PER_VI * efx_vf_size(efx));
kfree(rxqs);
efx_vfdi_flush_clear(vf);
vf->evq0_count = 0;
return timeout ? 0 : VFDI_RC_ETIMEDOUT;
}
static int efx_vfdi_insert_filter(struct efx_vf *vf)
{
struct efx_nic *efx = vf->efx;
struct vfdi_req *req = vf->buf.addr;
unsigned vf_rxq = req->u.mac_filter.rxq;
unsigned flags;
if (bad_vf_index(efx, vf_rxq) || vf->rx_filtering) {
if (net_ratelimit())
netif_err(efx, hw, efx->net_dev,
"ERROR: Invalid INSERT_FILTER from %s: rxq %d "
"flags 0x%x\n", vf->pci_name, vf_rxq,
req->u.mac_filter.flags);
return VFDI_RC_EINVAL;
}
flags = 0;
if (req->u.mac_filter.flags & VFDI_MAC_FILTER_FLAG_RSS)
flags |= EFX_FILTER_FLAG_RX_RSS;
if (req->u.mac_filter.flags & VFDI_MAC_FILTER_FLAG_SCATTER)
flags |= EFX_FILTER_FLAG_RX_SCATTER;
vf->rx_filter_flags = flags;
vf->rx_filter_qid = vf_rxq;
vf->rx_filtering = true;
efx_sriov_reset_rx_filter(vf);
queue_work(vfdi_workqueue, &efx->peer_work);
return VFDI_RC_SUCCESS;
}
static int efx_vfdi_remove_all_filters(struct efx_vf *vf)
{
vf->rx_filtering = false;
efx_sriov_reset_rx_filter(vf);
queue_work(vfdi_workqueue, &vf->efx->peer_work);
return VFDI_RC_SUCCESS;
}
static int efx_vfdi_set_status_page(struct efx_vf *vf)
{
struct efx_nic *efx = vf->efx;
struct vfdi_req *req = vf->buf.addr;
unsigned int page_count;
page_count = req->u.set_status_page.peer_page_count;
if (!req->u.set_status_page.dma_addr || EFX_PAGE_SIZE <
offsetof(struct vfdi_req,
u.set_status_page.peer_page_addr[page_count])) {
if (net_ratelimit())
netif_err(efx, hw, efx->net_dev,
"ERROR: Invalid SET_STATUS_PAGE from %s\n",
vf->pci_name);
return VFDI_RC_EINVAL;
}
mutex_lock(&efx->local_lock);
mutex_lock(&vf->status_lock);
vf->status_addr = req->u.set_status_page.dma_addr;
kfree(vf->peer_page_addrs);
vf->peer_page_addrs = NULL;
vf->peer_page_count = 0;
if (page_count) {
vf->peer_page_addrs = kcalloc(page_count, sizeof(u64),
GFP_KERNEL);
if (vf->peer_page_addrs) {
memcpy(vf->peer_page_addrs,
req->u.set_status_page.peer_page_addr,
page_count * sizeof(u64));
vf->peer_page_count = page_count;
}
}
__efx_sriov_push_vf_status(vf);
mutex_unlock(&vf->status_lock);
mutex_unlock(&efx->local_lock);
return VFDI_RC_SUCCESS;
}
static int efx_vfdi_clear_status_page(struct efx_vf *vf)
{
mutex_lock(&vf->status_lock);
vf->status_addr = 0;
mutex_unlock(&vf->status_lock);
return VFDI_RC_SUCCESS;
}
typedef int (*efx_vfdi_op_t)(struct efx_vf *vf);
static const efx_vfdi_op_t vfdi_ops[VFDI_OP_LIMIT] = {
[VFDI_OP_INIT_EVQ] = efx_vfdi_init_evq,
[VFDI_OP_INIT_TXQ] = efx_vfdi_init_txq,
[VFDI_OP_INIT_RXQ] = efx_vfdi_init_rxq,
[VFDI_OP_FINI_ALL_QUEUES] = efx_vfdi_fini_all_queues,
[VFDI_OP_INSERT_FILTER] = efx_vfdi_insert_filter,
[VFDI_OP_REMOVE_ALL_FILTERS] = efx_vfdi_remove_all_filters,
[VFDI_OP_SET_STATUS_PAGE] = efx_vfdi_set_status_page,
[VFDI_OP_CLEAR_STATUS_PAGE] = efx_vfdi_clear_status_page,
};
static void efx_sriov_vfdi(struct work_struct *work)
{
struct efx_vf *vf = container_of(work, struct efx_vf, req);
struct efx_nic *efx = vf->efx;
struct vfdi_req *req = vf->buf.addr;
struct efx_memcpy_req copy[2];
int rc;
/* Copy this page into the local address space */
memset(copy, '\0', sizeof(copy));
copy[0].from_rid = vf->pci_rid;
copy[0].from_addr = vf->req_addr;
copy[0].to_rid = efx->pci_dev->devfn;
copy[0].to_addr = vf->buf.dma_addr;
copy[0].length = EFX_PAGE_SIZE;
rc = efx_sriov_memcpy(efx, copy, 1);
if (rc) {
/* If we can't get the request, we can't reply to the caller */
if (net_ratelimit())
netif_err(efx, hw, efx->net_dev,
"ERROR: Unable to fetch VFDI request from %s rc %d\n",
vf->pci_name, -rc);
vf->busy = false;
return;
}
if (req->op < VFDI_OP_LIMIT && vfdi_ops[req->op] != NULL) {
rc = vfdi_ops[req->op](vf);
if (rc == 0) {
netif_dbg(efx, hw, efx->net_dev,
"vfdi request %d from %s ok\n",
req->op, vf->pci_name);
}
} else {
netif_dbg(efx, hw, efx->net_dev,
"ERROR: Unrecognised request %d from VF %s addr "
"%llx\n", req->op, vf->pci_name,
(unsigned long long)vf->req_addr);
rc = VFDI_RC_EOPNOTSUPP;
}
/* Allow subsequent VF requests */
vf->busy = false;
smp_wmb();
/* Respond to the request */
req->rc = rc;
req->op = VFDI_OP_RESPONSE;
memset(copy, '\0', sizeof(copy));
copy[0].from_buf = &req->rc;
copy[0].to_rid = vf->pci_rid;
copy[0].to_addr = vf->req_addr + offsetof(struct vfdi_req, rc);
copy[0].length = sizeof(req->rc);
copy[1].from_buf = &req->op;
copy[1].to_rid = vf->pci_rid;
copy[1].to_addr = vf->req_addr + offsetof(struct vfdi_req, op);
copy[1].length = sizeof(req->op);
(void) efx_sriov_memcpy(efx, copy, ARRAY_SIZE(copy));
}
/* After a reset the event queues inside the guests no longer exist. Fill the
* event ring in guest memory with VFDI reset events, then (re-initialise) the
* event queue to raise an interrupt. The guest driver will then recover.
*/
static void efx_sriov_reset_vf(struct efx_vf *vf, struct efx_buffer *buffer)
{
struct efx_nic *efx = vf->efx;
struct efx_memcpy_req copy_req[4];
efx_qword_t event;
unsigned int pos, count, k, buftbl, abs_evq;
efx_oword_t reg;
efx_dword_t ptr;
int rc;
BUG_ON(buffer->len != EFX_PAGE_SIZE);
if (!vf->evq0_count)
return;
BUG_ON(vf->evq0_count & (vf->evq0_count - 1));
mutex_lock(&vf->status_lock);
EFX_POPULATE_QWORD_3(event,
FSF_AZ_EV_CODE, FSE_CZ_EV_CODE_USER_EV,
VFDI_EV_SEQ, vf->msg_seqno,
VFDI_EV_TYPE, VFDI_EV_TYPE_RESET);
vf->msg_seqno++;
for (pos = 0; pos < EFX_PAGE_SIZE; pos += sizeof(event))
memcpy(buffer->addr + pos, &event, sizeof(event));
for (pos = 0; pos < vf->evq0_count; pos += count) {
count = min_t(unsigned, vf->evq0_count - pos,
ARRAY_SIZE(copy_req));
for (k = 0; k < count; k++) {
copy_req[k].from_buf = NULL;
copy_req[k].from_rid = efx->pci_dev->devfn;
copy_req[k].from_addr = buffer->dma_addr;
copy_req[k].to_rid = vf->pci_rid;
copy_req[k].to_addr = vf->evq0_addrs[pos + k];
copy_req[k].length = EFX_PAGE_SIZE;
}
rc = efx_sriov_memcpy(efx, copy_req, count);
if (rc) {
if (net_ratelimit())
netif_err(efx, hw, efx->net_dev,
"ERROR: Unable to notify %s of reset"
": %d\n", vf->pci_name, -rc);
break;
}
}
/* Reinitialise, arm and trigger evq0 */
abs_evq = abs_index(vf, 0);
buftbl = EFX_BUFTBL_EVQ_BASE(vf, 0);
efx_sriov_bufs(efx, buftbl, vf->evq0_addrs, vf->evq0_count);
EFX_POPULATE_OWORD_3(reg,
FRF_CZ_TIMER_Q_EN, 1,
FRF_CZ_HOST_NOTIFY_MODE, 0,
FRF_CZ_TIMER_MODE, FFE_CZ_TIMER_MODE_DIS);
efx_writeo_table(efx, &reg, FR_BZ_TIMER_TBL, abs_evq);
EFX_POPULATE_OWORD_3(reg,
FRF_AZ_EVQ_EN, 1,
FRF_AZ_EVQ_SIZE, __ffs(vf->evq0_count),
FRF_AZ_EVQ_BUF_BASE_ID, buftbl);
efx_writeo_table(efx, &reg, FR_BZ_EVQ_PTR_TBL, abs_evq);
EFX_POPULATE_DWORD_1(ptr, FRF_AZ_EVQ_RPTR, 0);
efx_writed_table(efx, &ptr, FR_BZ_EVQ_RPTR, abs_evq);
mutex_unlock(&vf->status_lock);
}
static void efx_sriov_reset_vf_work(struct work_struct *work)
{
struct efx_vf *vf = container_of(work, struct efx_vf, req);
struct efx_nic *efx = vf->efx;
struct efx_buffer buf;
if (!efx_nic_alloc_buffer(efx, &buf, EFX_PAGE_SIZE)) {
efx_sriov_reset_vf(vf, &buf);
efx_nic_free_buffer(efx, &buf);
}
}
static void efx_sriov_handle_no_channel(struct efx_nic *efx)
{
netif_err(efx, drv, efx->net_dev,
"ERROR: IOV requires MSI-X and 1 additional interrupt"
"vector. IOV disabled\n");
efx->vf_count = 0;
}
static int efx_sriov_probe_channel(struct efx_channel *channel)
{
channel->efx->vfdi_channel = channel;
return 0;
}
static void
efx_sriov_get_channel_name(struct efx_channel *channel, char *buf, size_t len)
{
snprintf(buf, len, "%s-iov", channel->efx->name);
}
static const struct efx_channel_type efx_sriov_channel_type = {
.handle_no_channel = efx_sriov_handle_no_channel,
.pre_probe = efx_sriov_probe_channel,
.get_name = efx_sriov_get_channel_name,
/* no copy operation; channel must not be reallocated */
.keep_eventq = true,
};
void efx_sriov_probe(struct efx_nic *efx)
{
unsigned count;
if (!max_vfs)
return;
if (efx_sriov_cmd(efx, false, &efx->vi_scale, &count))
return;
if (count > 0 && count > max_vfs)
count = max_vfs;
/* efx_nic_dimension_resources() will reduce vf_count as appopriate */
efx->vf_count = count;
efx->extra_channel_type[EFX_EXTRA_CHANNEL_IOV] = &efx_sriov_channel_type;
}
/* Copy the list of individual addresses into the vfdi_status.peers
* array and auxillary pages, protected by %local_lock. Drop that lock
* and then broadcast the address list to every VF.
*/
static void efx_sriov_peer_work(struct work_struct *data)
{
struct efx_nic *efx = container_of(data, struct efx_nic, peer_work);
struct vfdi_status *vfdi_status = efx->vfdi_status.addr;
struct efx_vf *vf;
struct efx_local_addr *local_addr;
struct vfdi_endpoint *peer;
struct efx_endpoint_page *epp;
struct list_head pages;
unsigned int peer_space;
unsigned int peer_count;
unsigned int pos;
mutex_lock(&efx->local_lock);
/* Move the existing peer pages off %local_page_list */
INIT_LIST_HEAD(&pages);
list_splice_tail_init(&efx->local_page_list, &pages);
/* Populate the VF addresses starting from entry 1 (entry 0 is
* the PF address)
*/
peer = vfdi_status->peers + 1;
peer_space = ARRAY_SIZE(vfdi_status->peers) - 1;
peer_count = 1;
for (pos = 0; pos < efx->vf_count; ++pos) {
vf = efx->vf + pos;
mutex_lock(&vf->status_lock);
if (vf->rx_filtering && !is_zero_ether_addr(vf->addr.mac_addr)) {
*peer++ = vf->addr;
++peer_count;
--peer_space;
BUG_ON(peer_space == 0);
}
mutex_unlock(&vf->status_lock);
}
/* Fill the remaining addresses */
list_for_each_entry(local_addr, &efx->local_addr_list, link) {
memcpy(peer->mac_addr, local_addr->addr, ETH_ALEN);
peer->tci = 0;
++peer;
++peer_count;
if (--peer_space == 0) {
if (list_empty(&pages)) {
epp = kmalloc(sizeof(*epp), GFP_KERNEL);
if (!epp)
break;
epp->ptr = dma_alloc_coherent(
&efx->pci_dev->dev, EFX_PAGE_SIZE,
&epp->addr, GFP_KERNEL);
if (!epp->ptr) {
kfree(epp);
break;
}
} else {
epp = list_first_entry(
&pages, struct efx_endpoint_page, link);
list_del(&epp->link);
}
list_add_tail(&epp->link, &efx->local_page_list);
peer = (struct vfdi_endpoint *)epp->ptr;
peer_space = EFX_PAGE_SIZE / sizeof(struct vfdi_endpoint);
}
}
vfdi_status->peer_count = peer_count;
mutex_unlock(&efx->local_lock);
/* Free any now unused endpoint pages */
while (!list_empty(&pages)) {
epp = list_first_entry(
&pages, struct efx_endpoint_page, link);
list_del(&epp->link);
dma_free_coherent(&efx->pci_dev->dev, EFX_PAGE_SIZE,
epp->ptr, epp->addr);
kfree(epp);
}
/* Finally, push the pages */
for (pos = 0; pos < efx->vf_count; ++pos) {
vf = efx->vf + pos;
mutex_lock(&vf->status_lock);
if (vf->status_addr)
__efx_sriov_push_vf_status(vf);
mutex_unlock(&vf->status_lock);
}
}
static void efx_sriov_free_local(struct efx_nic *efx)
{
struct efx_local_addr *local_addr;
struct efx_endpoint_page *epp;
while (!list_empty(&efx->local_addr_list)) {
local_addr = list_first_entry(&efx->local_addr_list,
struct efx_local_addr, link);
list_del(&local_addr->link);
kfree(local_addr);
}
while (!list_empty(&efx->local_page_list)) {
epp = list_first_entry(&efx->local_page_list,
struct efx_endpoint_page, link);
list_del(&epp->link);
dma_free_coherent(&efx->pci_dev->dev, EFX_PAGE_SIZE,
epp->ptr, epp->addr);
kfree(epp);
}
}
static int efx_sriov_vf_alloc(struct efx_nic *efx)
{
unsigned index;
struct efx_vf *vf;
efx->vf = kzalloc(sizeof(struct efx_vf) * efx->vf_count, GFP_KERNEL);
if (!efx->vf)
return -ENOMEM;
for (index = 0; index < efx->vf_count; ++index) {
vf = efx->vf + index;
vf->efx = efx;
vf->index = index;
vf->rx_filter_id = -1;
vf->tx_filter_mode = VF_TX_FILTER_AUTO;
vf->tx_filter_id = -1;
INIT_WORK(&vf->req, efx_sriov_vfdi);
INIT_WORK(&vf->reset_work, efx_sriov_reset_vf_work);
init_waitqueue_head(&vf->flush_waitq);
mutex_init(&vf->status_lock);
mutex_init(&vf->txq_lock);
}
return 0;
}
static void efx_sriov_vfs_fini(struct efx_nic *efx)
{
struct efx_vf *vf;
unsigned int pos;
for (pos = 0; pos < efx->vf_count; ++pos) {
vf = efx->vf + pos;
efx_nic_free_buffer(efx, &vf->buf);
kfree(vf->peer_page_addrs);
vf->peer_page_addrs = NULL;
vf->peer_page_count = 0;
vf->evq0_count = 0;
}
}
static int efx_sriov_vfs_init(struct efx_nic *efx)
{
struct pci_dev *pci_dev = efx->pci_dev;
unsigned index, devfn, sriov, buftbl_base;
u16 offset, stride;
struct efx_vf *vf;
int rc;
sriov = pci_find_ext_capability(pci_dev, PCI_EXT_CAP_ID_SRIOV);
if (!sriov)
return -ENOENT;
pci_read_config_word(pci_dev, sriov + PCI_SRIOV_VF_OFFSET, &offset);
pci_read_config_word(pci_dev, sriov + PCI_SRIOV_VF_STRIDE, &stride);
buftbl_base = efx->vf_buftbl_base;
devfn = pci_dev->devfn + offset;
for (index = 0; index < efx->vf_count; ++index) {
vf = efx->vf + index;
/* Reserve buffer entries */
vf->buftbl_base = buftbl_base;
buftbl_base += EFX_VF_BUFTBL_PER_VI * efx_vf_size(efx);
vf->pci_rid = devfn;
snprintf(vf->pci_name, sizeof(vf->pci_name),
"%04x:%02x:%02x.%d",
pci_domain_nr(pci_dev->bus), pci_dev->bus->number,
PCI_SLOT(devfn), PCI_FUNC(devfn));
rc = efx_nic_alloc_buffer(efx, &vf->buf, EFX_PAGE_SIZE);
if (rc)
goto fail;
devfn += stride;
}
return 0;
fail:
efx_sriov_vfs_fini(efx);
return rc;
}
int efx_sriov_init(struct efx_nic *efx)
{
struct net_device *net_dev = efx->net_dev;
struct vfdi_status *vfdi_status;
int rc;
/* Ensure there's room for vf_channel */
BUILD_BUG_ON(EFX_MAX_CHANNELS + 1 >= EFX_VI_BASE);
/* Ensure that VI_BASE is aligned on VI_SCALE */
BUILD_BUG_ON(EFX_VI_BASE & ((1 << EFX_VI_SCALE_MAX) - 1));
if (efx->vf_count == 0)
return 0;
rc = efx_sriov_cmd(efx, true, NULL, NULL);
if (rc)
goto fail_cmd;
rc = efx_nic_alloc_buffer(efx, &efx->vfdi_status, sizeof(*vfdi_status));
if (rc)
goto fail_status;
vfdi_status = efx->vfdi_status.addr;
memset(vfdi_status, 0, sizeof(*vfdi_status));
vfdi_status->version = 1;
vfdi_status->length = sizeof(*vfdi_status);
vfdi_status->max_tx_channels = vf_max_tx_channels;
vfdi_status->vi_scale = efx->vi_scale;
vfdi_status->rss_rxq_count = efx->rss_spread;
vfdi_status->peer_count = 1 + efx->vf_count;
vfdi_status->timer_quantum_ns = efx->timer_quantum_ns;
rc = efx_sriov_vf_alloc(efx);
if (rc)
goto fail_alloc;
mutex_init(&efx->local_lock);
INIT_WORK(&efx->peer_work, efx_sriov_peer_work);
INIT_LIST_HEAD(&efx->local_addr_list);
INIT_LIST_HEAD(&efx->local_page_list);
rc = efx_sriov_vfs_init(efx);
if (rc)
goto fail_vfs;
rtnl_lock();
memcpy(vfdi_status->peers[0].mac_addr,
net_dev->dev_addr, ETH_ALEN);
efx->vf_init_count = efx->vf_count;
rtnl_unlock();
efx_sriov_usrev(efx, true);
/* At this point we must be ready to accept VFDI requests */
rc = pci_enable_sriov(efx->pci_dev, efx->vf_count);
if (rc)
goto fail_pci;
netif_info(efx, probe, net_dev,
"enabled SR-IOV for %d VFs, %d VI per VF\n",
efx->vf_count, efx_vf_size(efx));
return 0;
fail_pci:
efx_sriov_usrev(efx, false);
rtnl_lock();
efx->vf_init_count = 0;
rtnl_unlock();
efx_sriov_vfs_fini(efx);
fail_vfs:
cancel_work_sync(&efx->peer_work);
efx_sriov_free_local(efx);
kfree(efx->vf);
fail_alloc:
efx_nic_free_buffer(efx, &efx->vfdi_status);
fail_status:
efx_sriov_cmd(efx, false, NULL, NULL);
fail_cmd:
return rc;
}
void efx_sriov_fini(struct efx_nic *efx)
{
struct efx_vf *vf;
unsigned int pos;
if (efx->vf_init_count == 0)
return;
/* Disable all interfaces to reconfiguration */
BUG_ON(efx->vfdi_channel->enabled);
efx_sriov_usrev(efx, false);
rtnl_lock();
efx->vf_init_count = 0;
rtnl_unlock();
/* Flush all reconfiguration work */
for (pos = 0; pos < efx->vf_count; ++pos) {
vf = efx->vf + pos;
cancel_work_sync(&vf->req);
cancel_work_sync(&vf->reset_work);
}
cancel_work_sync(&efx->peer_work);
pci_disable_sriov(efx->pci_dev);
/* Tear down back-end state */
efx_sriov_vfs_fini(efx);
efx_sriov_free_local(efx);
kfree(efx->vf);
efx_nic_free_buffer(efx, &efx->vfdi_status);
efx_sriov_cmd(efx, false, NULL, NULL);
}
void efx_sriov_event(struct efx_channel *channel, efx_qword_t *event)
{
struct efx_nic *efx = channel->efx;
struct efx_vf *vf;
unsigned qid, seq, type, data;
qid = EFX_QWORD_FIELD(*event, FSF_CZ_USER_QID);
/* USR_EV_REG_VALUE is dword0, so access the VFDI_EV fields directly */
BUILD_BUG_ON(FSF_CZ_USER_EV_REG_VALUE_LBN != 0);
seq = EFX_QWORD_FIELD(*event, VFDI_EV_SEQ);
type = EFX_QWORD_FIELD(*event, VFDI_EV_TYPE);
data = EFX_QWORD_FIELD(*event, VFDI_EV_DATA);
netif_vdbg(efx, hw, efx->net_dev,
"USR_EV event from qid %d seq 0x%x type %d data 0x%x\n",
qid, seq, type, data);
if (map_vi_index(efx, qid, &vf, NULL))
return;
if (vf->busy)
goto error;
if (type == VFDI_EV_TYPE_REQ_WORD0) {
/* Resynchronise */
vf->req_type = VFDI_EV_TYPE_REQ_WORD0;
vf->req_seqno = seq + 1;
vf->req_addr = 0;
} else if (seq != (vf->req_seqno++ & 0xff) || type != vf->req_type)
goto error;
switch (vf->req_type) {
case VFDI_EV_TYPE_REQ_WORD0:
case VFDI_EV_TYPE_REQ_WORD1:
case VFDI_EV_TYPE_REQ_WORD2:
vf->req_addr |= (u64)data << (vf->req_type << 4);
++vf->req_type;
return;
case VFDI_EV_TYPE_REQ_WORD3:
vf->req_addr |= (u64)data << 48;
vf->req_type = VFDI_EV_TYPE_REQ_WORD0;
vf->busy = true;
queue_work(vfdi_workqueue, &vf->req);
return;
}
error:
if (net_ratelimit())
netif_err(efx, hw, efx->net_dev,
"ERROR: Screaming VFDI request from %s\n",
vf->pci_name);
/* Reset the request and sequence number */
vf->req_type = VFDI_EV_TYPE_REQ_WORD0;
vf->req_seqno = seq + 1;
}
void efx_sriov_flr(struct efx_nic *efx, unsigned vf_i)
{
struct efx_vf *vf;
if (vf_i > efx->vf_init_count)
return;
vf = efx->vf + vf_i;
netif_info(efx, hw, efx->net_dev,
"FLR on VF %s\n", vf->pci_name);
vf->status_addr = 0;
efx_vfdi_remove_all_filters(vf);
efx_vfdi_flush_clear(vf);
vf->evq0_count = 0;
}
void efx_sriov_mac_address_changed(struct efx_nic *efx)
{
struct vfdi_status *vfdi_status = efx->vfdi_status.addr;
if (!efx->vf_init_count)
return;
memcpy(vfdi_status->peers[0].mac_addr,
efx->net_dev->dev_addr, ETH_ALEN);
queue_work(vfdi_workqueue, &efx->peer_work);
}
void efx_sriov_tx_flush_done(struct efx_nic *efx, efx_qword_t *event)
{
struct efx_vf *vf;
unsigned queue, qid;
queue = EFX_QWORD_FIELD(*event, FSF_AZ_DRIVER_EV_SUBDATA);
if (map_vi_index(efx, queue, &vf, &qid))
return;
/* Ignore flush completions triggered by an FLR */
if (!test_bit(qid, vf->txq_mask))
return;
__clear_bit(qid, vf->txq_mask);
--vf->txq_count;
if (efx_vfdi_flush_wake(vf))
wake_up(&vf->flush_waitq);
}
void efx_sriov_rx_flush_done(struct efx_nic *efx, efx_qword_t *event)
{
struct efx_vf *vf;
unsigned ev_failed, queue, qid;
queue = EFX_QWORD_FIELD(*event, FSF_AZ_DRIVER_EV_RX_DESCQ_ID);
ev_failed = EFX_QWORD_FIELD(*event,
FSF_AZ_DRIVER_EV_RX_FLUSH_FAIL);
if (map_vi_index(efx, queue, &vf, &qid))
return;
if (!test_bit(qid, vf->rxq_mask))
return;
if (ev_failed) {
set_bit(qid, vf->rxq_retry_mask);
atomic_inc(&vf->rxq_retry_count);
} else {
__clear_bit(qid, vf->rxq_mask);
--vf->rxq_count;
}
if (efx_vfdi_flush_wake(vf))
wake_up(&vf->flush_waitq);
}
/* Called from napi. Schedule the reset work item */
void efx_sriov_desc_fetch_err(struct efx_nic *efx, unsigned dmaq)
{
struct efx_vf *vf;
unsigned int rel;
if (map_vi_index(efx, dmaq, &vf, &rel))
return;
if (net_ratelimit())
netif_err(efx, hw, efx->net_dev,
"VF %d DMA Q %d reports descriptor fetch error.\n",
vf->index, rel);
queue_work(vfdi_workqueue, &vf->reset_work);
}
/* Reset all VFs */
void efx_sriov_reset(struct efx_nic *efx)
{
unsigned int vf_i;
struct efx_buffer buf;
struct efx_vf *vf;
ASSERT_RTNL();
if (efx->vf_init_count == 0)
return;
efx_sriov_usrev(efx, true);
(void)efx_sriov_cmd(efx, true, NULL, NULL);
if (efx_nic_alloc_buffer(efx, &buf, EFX_PAGE_SIZE))
return;
for (vf_i = 0; vf_i < efx->vf_init_count; ++vf_i) {
vf = efx->vf + vf_i;
efx_sriov_reset_vf(vf, &buf);
}
efx_nic_free_buffer(efx, &buf);
}
int efx_init_sriov(void)
{
/* A single threaded workqueue is sufficient. efx_sriov_vfdi() and
* efx_sriov_peer_work() spend almost all their time sleeping for
* MCDI to complete anyway
*/
vfdi_workqueue = create_singlethread_workqueue("sfc_vfdi");
if (!vfdi_workqueue)
return -ENOMEM;
return 0;
}
void efx_fini_sriov(void)
{
destroy_workqueue(vfdi_workqueue);
}
int efx_sriov_set_vf_mac(struct net_device *net_dev, int vf_i, u8 *mac)
{
struct efx_nic *efx = netdev_priv(net_dev);
struct efx_vf *vf;
if (vf_i >= efx->vf_init_count)
return -EINVAL;
vf = efx->vf + vf_i;
mutex_lock(&vf->status_lock);
memcpy(vf->addr.mac_addr, mac, ETH_ALEN);
__efx_sriov_update_vf_addr(vf);
mutex_unlock(&vf->status_lock);
return 0;
}
int efx_sriov_set_vf_vlan(struct net_device *net_dev, int vf_i,
u16 vlan, u8 qos)
{
struct efx_nic *efx = netdev_priv(net_dev);
struct efx_vf *vf;
u16 tci;
if (vf_i >= efx->vf_init_count)
return -EINVAL;
vf = efx->vf + vf_i;
mutex_lock(&vf->status_lock);
tci = (vlan & VLAN_VID_MASK) | ((qos & 0x7) << VLAN_PRIO_SHIFT);
vf->addr.tci = htons(tci);
__efx_sriov_update_vf_addr(vf);
mutex_unlock(&vf->status_lock);
return 0;
}
int efx_sriov_set_vf_spoofchk(struct net_device *net_dev, int vf_i,
bool spoofchk)
{
struct efx_nic *efx = netdev_priv(net_dev);
struct efx_vf *vf;
int rc;
if (vf_i >= efx->vf_init_count)
return -EINVAL;
vf = efx->vf + vf_i;
mutex_lock(&vf->txq_lock);
if (vf->txq_count == 0) {
vf->tx_filter_mode =
spoofchk ? VF_TX_FILTER_ON : VF_TX_FILTER_OFF;
rc = 0;
} else {
/* This cannot be changed while TX queues are running */
rc = -EBUSY;
}
mutex_unlock(&vf->txq_lock);
return rc;
}
int efx_sriov_get_vf_config(struct net_device *net_dev, int vf_i,
struct ifla_vf_info *ivi)
{
struct efx_nic *efx = netdev_priv(net_dev);
struct efx_vf *vf;
u16 tci;
if (vf_i >= efx->vf_init_count)
return -EINVAL;
vf = efx->vf + vf_i;
ivi->vf = vf_i;
memcpy(ivi->mac, vf->addr.mac_addr, ETH_ALEN);
ivi->tx_rate = 0;
tci = ntohs(vf->addr.tci);
ivi->vlan = tci & VLAN_VID_MASK;
ivi->qos = (tci >> VLAN_PRIO_SHIFT) & 0x7;
ivi->spoofchk = vf->tx_filter_mode == VF_TX_FILTER_ON;
return 0;
}
......@@ -110,7 +110,7 @@ efx_max_tx_len(struct efx_nic *efx, dma_addr_t dma_addr)
* little benefit from using descriptors that cross those
* boundaries and we keep things simple by not doing so.
*/
unsigned len = (~dma_addr & 0xfff) + 1;
unsigned len = (~dma_addr & (EFX_PAGE_SIZE - 1)) + 1;
/* Work around hardware bug for unaligned buffers. */
if (EFX_WORKAROUND_5391(efx) && (dma_addr & 0xf))
......
/****************************************************************************
* Driver for Solarflare Solarstorm network controllers and boards
* Copyright 2010-2012 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.
*/
#ifndef _VFDI_H
#define _VFDI_H
/**
* DOC: Virtual Function Driver Interface
*
* This file contains software structures used to form a two way
* communication channel between the VF driver and the PF driver,
* named Virtual Function Driver Interface (VFDI).
*
* For the purposes of VFDI, a page is a memory region with size and
* alignment of 4K. All addresses are DMA addresses to be used within
* the domain of the relevant VF.
*
* The only hardware-defined channels for a VF driver to communicate
* with the PF driver are the event mailboxes (%FR_CZ_USR_EV
* registers). Writing to these registers generates an event with
* EV_CODE = EV_CODE_USR_EV, USER_QID set to the index of the mailbox
* and USER_EV_REG_VALUE set to the value written. The PF driver may
* direct or disable delivery of these events by setting
* %FR_CZ_USR_EV_CFG.
*
* The PF driver can send arbitrary events to arbitrary event queues.
* However, for consistency, VFDI events from the PF are defined to
* follow the same form and be sent to the first event queue assigned
* to the VF while that queue is enabled by the VF driver.
*
* The general form of the variable bits of VFDI events is:
*
* 0 16 24 31
* | DATA | TYPE | SEQ |
*
* SEQ is a sequence number which should be incremented by 1 (modulo
* 256) for each event. The sequence numbers used in each direction
* are independent.
*
* The VF submits requests of type &struct vfdi_req by sending the
* address of the request (ADDR) in a series of 4 events:
*
* 0 16 24 31
* | ADDR[0:15] | VFDI_EV_TYPE_REQ_WORD0 | SEQ |
* | ADDR[16:31] | VFDI_EV_TYPE_REQ_WORD1 | SEQ+1 |
* | ADDR[32:47] | VFDI_EV_TYPE_REQ_WORD2 | SEQ+2 |
* | ADDR[48:63] | VFDI_EV_TYPE_REQ_WORD3 | SEQ+3 |
*
* The address must be page-aligned. After receiving such a valid
* series of events, the PF driver will attempt to read the request
* and write a response to the same address. In case of an invalid
* sequence of events or a DMA error, there will be no response.
*
* The VF driver may request that the PF driver writes status
* information into its domain asynchronously. After writing the
* status, the PF driver will send an event of the form:
*
* 0 16 24 31
* | reserved | VFDI_EV_TYPE_STATUS | SEQ |
*
* In case the VF must be reset for any reason, the PF driver will
* send an event of the form:
*
* 0 16 24 31
* | reserved | VFDI_EV_TYPE_RESET | SEQ |
*
* It is then the responsibility of the VF driver to request
* reinitialisation of its queues.
*/
#define VFDI_EV_SEQ_LBN 24
#define VFDI_EV_SEQ_WIDTH 8
#define VFDI_EV_TYPE_LBN 16
#define VFDI_EV_TYPE_WIDTH 8
#define VFDI_EV_TYPE_REQ_WORD0 0
#define VFDI_EV_TYPE_REQ_WORD1 1
#define VFDI_EV_TYPE_REQ_WORD2 2
#define VFDI_EV_TYPE_REQ_WORD3 3
#define VFDI_EV_TYPE_STATUS 4
#define VFDI_EV_TYPE_RESET 5
#define VFDI_EV_DATA_LBN 0
#define VFDI_EV_DATA_WIDTH 16
struct vfdi_endpoint {
u8 mac_addr[ETH_ALEN];
__be16 tci;
};
/**
* enum vfdi_op - VFDI operation enumeration
* @VFDI_OP_RESPONSE: Indicates a response to the request.
* @VFDI_OP_INIT_EVQ: Initialize SRAM entries and initialize an EVQ.
* @VFDI_OP_INIT_RXQ: Initialize SRAM entries and initialize an RXQ.
* @VFDI_OP_INIT_TXQ: Initialize SRAM entries and initialize a TXQ.
* @VFDI_OP_FINI_ALL_QUEUES: Flush all queues, finalize all queues, then
* finalize the SRAM entries.
* @VFDI_OP_INSERT_FILTER: Insert a MAC filter targetting the given RXQ.
* @VFDI_OP_REMOVE_ALL_FILTERS: Remove all filters.
* @VFDI_OP_SET_STATUS_PAGE: Set the DMA page(s) used for status updates
* from PF and write the initial status.
* @VFDI_OP_CLEAR_STATUS_PAGE: Clear the DMA page(s) used for status
* updates from PF.
*/
enum vfdi_op {
VFDI_OP_RESPONSE = 0,
VFDI_OP_INIT_EVQ = 1,
VFDI_OP_INIT_RXQ = 2,
VFDI_OP_INIT_TXQ = 3,
VFDI_OP_FINI_ALL_QUEUES = 4,
VFDI_OP_INSERT_FILTER = 5,
VFDI_OP_REMOVE_ALL_FILTERS = 6,
VFDI_OP_SET_STATUS_PAGE = 7,
VFDI_OP_CLEAR_STATUS_PAGE = 8,
VFDI_OP_LIMIT,
};
/* Response codes for VFDI operations. Other values may be used in future. */
#define VFDI_RC_SUCCESS 0
#define VFDI_RC_ENOMEM (-12)
#define VFDI_RC_EINVAL (-22)
#define VFDI_RC_EOPNOTSUPP (-95)
#define VFDI_RC_ETIMEDOUT (-110)
/**
* struct vfdi_req - Request from VF driver to PF driver
* @op: Operation code or response indicator, taken from &enum vfdi_op.
* @rc: Response code. Set to 0 on success or a negative error code on failure.
* @u.init_evq.index: Index of event queue to create.
* @u.init_evq.buf_count: Number of 4k buffers backing event queue.
* @u.init_evq.addr: Array of length %u.init_evq.buf_count containing DMA
* address of each page backing the event queue.
* @u.init_rxq.index: Index of receive queue to create.
* @u.init_rxq.buf_count: Number of 4k buffers backing receive queue.
* @u.init_rxq.evq: Instance of event queue to target receive events at.
* @u.init_rxq.label: Label used in receive events.
* @u.init_rxq.flags: Unused.
* @u.init_rxq.addr: Array of length %u.init_rxq.buf_count containing DMA
* address of each page backing the receive queue.
* @u.init_txq.index: Index of transmit queue to create.
* @u.init_txq.buf_count: Number of 4k buffers backing transmit queue.
* @u.init_txq.evq: Instance of event queue to target transmit completion
* events at.
* @u.init_txq.label: Label used in transmit completion events.
* @u.init_txq.flags: Checksum offload flags.
* @u.init_txq.addr: Array of length %u.init_txq.buf_count containing DMA
* address of each page backing the transmit queue.
* @u.mac_filter.rxq: Insert MAC filter at VF local address/VLAN targetting
* all traffic at this receive queue.
* @u.mac_filter.flags: MAC filter flags.
* @u.set_status_page.dma_addr: Base address for the &struct vfdi_status.
* This address must be such that the structure fits within a page.
* @u.set_status_page.peer_page_count: Number of additional pages the VF
* has provided into which peer addresses may be DMAd.
* @u.set_status_page.peer_page_addr: Array of DMA addresses of pages.
* If the number of peers exceeds 256, then the VF must provide
* additional pages in this array. The PF will then DMA up to
* 512 vfdi_endpoint structures into each page. These addresses
* must be page-aligned.
*/
struct vfdi_req {
u32 op;
u32 reserved1;
s32 rc;
u32 reserved2;
union {
struct {
u32 index;
u32 buf_count;
u64 addr[];
} init_evq;
struct {
u32 index;
u32 buf_count;
u32 evq;
u32 label;
u32 flags;
#define VFDI_RXQ_FLAG_SCATTER_EN 1
u32 reserved;
u64 addr[];
} init_rxq;
struct {
u32 index;
u32 buf_count;
u32 evq;
u32 label;
u32 flags;
#define VFDI_TXQ_FLAG_IP_CSUM_DIS 1
#define VFDI_TXQ_FLAG_TCPUDP_CSUM_DIS 2
u32 reserved;
u64 addr[];
} init_txq;
struct {
u32 rxq;
u32 flags;
#define VFDI_MAC_FILTER_FLAG_RSS 1
#define VFDI_MAC_FILTER_FLAG_SCATTER 2
} mac_filter;
struct {
u64 dma_addr;
u64 peer_page_count;
u64 peer_page_addr[];
} set_status_page;
} u;
};
/**
* struct vfdi_status - Status provided by PF driver to VF driver
* @generation_start: A generation count DMA'd to VF *before* the
* rest of the structure.
* @generation_end: A generation count DMA'd to VF *after* the
* rest of the structure.
* @version: Version of this structure; currently set to 1. Later
* versions must either be layout-compatible or only be sent to VFs
* that specifically request them.
* @length: Total length of this structure including embedded tables
* @vi_scale: log2 the number of VIs available on this VF. This quantity
* is used by the hardware for register decoding.
* @max_tx_channels: The maximum number of transmit queues the VF can use.
* @rss_rxq_count: The number of receive queues present in the shared RSS
* indirection table.
* @peer_count: Total number of peers in the complete peer list. If larger
* than ARRAY_SIZE(%peers), then the VF must provide sufficient
* additional pages each of which is filled with vfdi_endpoint structures.
* @local: The MAC address and outer VLAN tag of *this* VF
* @peers: Table of peer addresses. The @tci fields in these structures
* are currently unused and must be ignored. Additional peers are
* written into any additional pages provided by the VF.
* @timer_quantum_ns: Timer quantum (nominal period between timer ticks)
* for interrupt moderation timers, in nanoseconds. This member is only
* present if @length is sufficiently large.
*/
struct vfdi_status {
u32 generation_start;
u32 generation_end;
u32 version;
u32 length;
u8 vi_scale;
u8 max_tx_channels;
u8 rss_rxq_count;
u8 reserved1;
u16 peer_count;
u16 reserved2;
struct vfdi_endpoint local;
struct vfdi_endpoint peers[256];
/* Members below here extend version 1 of this structure */
u32 timer_quantum_ns;
};
#endif
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