Commit 7f967c01 authored by Ben Hutchings's avatar Ben Hutchings

sfc: Add support for 'extra' channel types

Abstract some of the channel operations to allow for 'extra'
channels that do not have RX or TX queues.

- Try to assign a channel to each extra channel type that is enabled
  for the NIC, but gracefully degrade if we can't allocate sufficient
  MSI-X vectors
- Allow each extra channel type to generate its own channel name
- Allow channel types to disable reallocation and reinitialisation
  of their channels
Signed-off-by: default avatarBen Hutchings <bhutchings@solarflare.com>
parent a16e5b24
...@@ -186,11 +186,13 @@ MODULE_PARM_DESC(debug, "Bitmapped debugging message enable value"); ...@@ -186,11 +186,13 @@ MODULE_PARM_DESC(debug, "Bitmapped debugging message enable value");
* *
*************************************************************************/ *************************************************************************/
static void efx_start_interrupts(struct efx_nic *efx); static void efx_start_interrupts(struct efx_nic *efx, bool may_keep_eventq);
static void efx_stop_interrupts(struct efx_nic *efx); 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 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_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(struct efx_nic *efx);
static void efx_fini_napi_channel(struct efx_channel *channel); static void efx_fini_napi_channel(struct efx_channel *channel);
static void efx_fini_struct(struct efx_nic *efx); static void efx_fini_struct(struct efx_nic *efx);
...@@ -439,8 +441,7 @@ static void efx_remove_eventq(struct efx_channel *channel) ...@@ -439,8 +441,7 @@ static void efx_remove_eventq(struct efx_channel *channel)
* *
*************************************************************************/ *************************************************************************/
/* Allocate and initialise a channel structure, optionally copying /* Allocate and initialise a channel structure. */
* parameters (but not resources) from an old channel structure. */
static struct efx_channel * static struct efx_channel *
efx_alloc_channel(struct efx_nic *efx, int i, struct efx_channel *old_channel) efx_alloc_channel(struct efx_nic *efx, int i, struct efx_channel *old_channel)
{ {
...@@ -449,45 +450,60 @@ efx_alloc_channel(struct efx_nic *efx, int i, struct efx_channel *old_channel) ...@@ -449,45 +450,60 @@ efx_alloc_channel(struct efx_nic *efx, int i, struct efx_channel *old_channel)
struct efx_tx_queue *tx_queue; struct efx_tx_queue *tx_queue;
int j; int j;
if (old_channel) { channel = kzalloc(sizeof(*channel), GFP_KERNEL);
channel = kmalloc(sizeof(*channel), GFP_KERNEL); if (!channel)
if (!channel) return NULL;
return NULL;
*channel = *old_channel; channel->efx = efx;
channel->channel = i;
channel->type = &efx_default_channel_type;
channel->napi_dev = NULL; for (j = 0; j < EFX_TXQ_TYPES; j++) {
memset(&channel->eventq, 0, sizeof(channel->eventq)); 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 = &channel->rx_queue;
rx_queue->buffer = NULL; rx_queue->efx = efx;
memset(&rx_queue->rxd, 0, sizeof(rx_queue->rxd)); setup_timer(&rx_queue->slow_fill, efx_rx_slow_fill,
(unsigned long)rx_queue);
for (j = 0; j < EFX_TXQ_TYPES; j++) { return channel;
tx_queue = &channel->tx_queue[j]; }
if (tx_queue->channel)
tx_queue->channel = channel; /* Allocate and initialise a channel structure, copying parameters
tx_queue->buffer = NULL; * (but not resources) from an old channel structure.
memset(&tx_queue->txd, 0, sizeof(tx_queue->txd)); */
} static struct efx_channel *
} else { efx_copy_channel(const struct efx_channel *old_channel)
channel = kzalloc(sizeof(*channel), GFP_KERNEL); {
if (!channel) struct efx_channel *channel;
return NULL; struct efx_rx_queue *rx_queue;
struct efx_tx_queue *tx_queue;
int j;
channel->efx = efx; channel = kmalloc(sizeof(*channel), GFP_KERNEL);
channel->channel = i; 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++) { for (j = 0; j < EFX_TXQ_TYPES; j++) {
tx_queue = &channel->tx_queue[j]; tx_queue = &channel->tx_queue[j];
tx_queue->efx = efx; if (tx_queue->channel)
tx_queue->queue = i * EFX_TXQ_TYPES + j;
tx_queue->channel = 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 = &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, setup_timer(&rx_queue->slow_fill, efx_rx_slow_fill,
(unsigned long)rx_queue); (unsigned long)rx_queue);
...@@ -503,57 +519,62 @@ static int efx_probe_channel(struct efx_channel *channel) ...@@ -503,57 +519,62 @@ static int efx_probe_channel(struct efx_channel *channel)
netif_dbg(channel->efx, probe, channel->efx->net_dev, netif_dbg(channel->efx, probe, channel->efx->net_dev,
"creating channel %d\n", channel->channel); "creating channel %d\n", channel->channel);
rc = channel->type->pre_probe(channel);
if (rc)
goto fail;
rc = efx_probe_eventq(channel); rc = efx_probe_eventq(channel);
if (rc) if (rc)
goto fail1; goto fail;
efx_for_each_channel_tx_queue(tx_queue, channel) { efx_for_each_channel_tx_queue(tx_queue, channel) {
rc = efx_probe_tx_queue(tx_queue); rc = efx_probe_tx_queue(tx_queue);
if (rc) if (rc)
goto fail2; goto fail;
} }
efx_for_each_channel_rx_queue(rx_queue, channel) { efx_for_each_channel_rx_queue(rx_queue, channel) {
rc = efx_probe_rx_queue(rx_queue); rc = efx_probe_rx_queue(rx_queue);
if (rc) if (rc)
goto fail3; goto fail;
} }
channel->n_rx_frm_trunc = 0; channel->n_rx_frm_trunc = 0;
return 0; return 0;
fail3: fail:
efx_for_each_channel_rx_queue(rx_queue, channel) efx_remove_channel(channel);
efx_remove_rx_queue(rx_queue);
fail2:
efx_for_each_channel_tx_queue(tx_queue, channel)
efx_remove_tx_queue(tx_queue);
fail1:
return rc; 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) static void efx_set_channel_names(struct efx_nic *efx)
{ {
struct efx_channel *channel; struct efx_channel *channel;
const char *type = "";
int number;
efx_for_each_channel(channel, efx) { efx_for_each_channel(channel, efx)
number = channel->channel; channel->type->get_name(channel,
if (efx->n_channels > efx->n_rx_channels) { efx->channel_name[channel->channel],
if (channel->channel < efx->n_rx_channels) { sizeof(efx->channel_name[0]));
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);
}
} }
static int efx_probe_channels(struct efx_nic *efx) static int efx_probe_channels(struct efx_nic *efx)
...@@ -697,16 +718,40 @@ efx_realloc_channels(struct efx_nic *efx, u32 rxq_entries, u32 txq_entries) ...@@ -697,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; struct efx_channel *other_channel[EFX_MAX_CHANNELS], *channel;
u32 old_rxq_entries, old_txq_entries; u32 old_rxq_entries, old_txq_entries;
unsigned i; unsigned i, next_buffer_table = 0;
int rc; 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_stop_all(efx);
efx_stop_interrupts(efx); efx_stop_interrupts(efx, true);
/* Clone channels */ /* Clone channels (where possible) */
memset(other_channel, 0, sizeof(other_channel)); memset(other_channel, 0, sizeof(other_channel));
for (i = 0; i < efx->n_channels; i++) { 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) { if (!channel) {
rc = -ENOMEM; rc = -ENOMEM;
goto out; goto out;
...@@ -725,23 +770,31 @@ efx_realloc_channels(struct efx_nic *efx, u32 rxq_entries, u32 txq_entries) ...@@ -725,23 +770,31 @@ efx_realloc_channels(struct efx_nic *efx, u32 rxq_entries, u32 txq_entries)
other_channel[i] = channel; other_channel[i] = channel;
} }
rc = efx_probe_channels(efx); /* Restart buffer table allocation */
if (rc) efx->next_buffer_table = next_buffer_table;
goto rollback;
efx_init_napi(efx);
/* Destroy old channels */
for (i = 0; i < efx->n_channels; i++) { for (i = 0; i < efx->n_channels; i++) {
efx_fini_napi_channel(other_channel[i]); channel = efx->channel[i];
efx_remove_channel(other_channel[i]); if (!channel->type->copy)
continue;
rc = efx_probe_channel(channel);
if (rc)
goto rollback;
efx_init_napi_channel(efx->channel[i]);
} }
out: out:
/* Free unused channel structures */ /* Destroy unused channel structures */
for (i = 0; i < efx->n_channels; i++) for (i = 0; i < efx->n_channels; i++) {
kfree(other_channel[i]); channel = other_channel[i];
if (channel && channel->type->copy) {
efx_fini_napi_channel(channel);
efx_remove_channel(channel);
kfree(channel);
}
}
efx_start_interrupts(efx); efx_start_interrupts(efx, true);
efx_start_all(efx); efx_start_all(efx);
return rc; return rc;
...@@ -762,6 +815,18 @@ void efx_schedule_slow_fill(struct efx_rx_queue *rx_queue) ...@@ -762,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)); 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 * Port handling
...@@ -1162,9 +1227,14 @@ static int efx_probe_interrupts(struct efx_nic *efx) ...@@ -1162,9 +1227,14 @@ static int efx_probe_interrupts(struct efx_nic *efx)
{ {
unsigned int max_channels = unsigned int max_channels =
min(efx->type->phys_addr_channels, EFX_MAX_CHANNELS); min(efx->type->phys_addr_channels, EFX_MAX_CHANNELS);
unsigned int i; unsigned int extra_channels = 0;
unsigned int i, j;
int rc; 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) { if (efx->interrupt_mode == EFX_INT_MODE_MSIX) {
struct msix_entry xentries[EFX_MAX_CHANNELS]; struct msix_entry xentries[EFX_MAX_CHANNELS];
unsigned int n_channels; unsigned int n_channels;
...@@ -1172,6 +1242,7 @@ static int efx_probe_interrupts(struct efx_nic *efx) ...@@ -1172,6 +1242,7 @@ static int efx_probe_interrupts(struct efx_nic *efx)
n_channels = efx_wanted_parallelism(); n_channels = efx_wanted_parallelism();
if (separate_tx_channels) if (separate_tx_channels)
n_channels *= 2; n_channels *= 2;
n_channels += extra_channels;
n_channels = min(n_channels, max_channels); n_channels = min(n_channels, max_channels);
for (i = 0; i < n_channels; i++) for (i = 0; i < n_channels; i++)
...@@ -1191,22 +1262,23 @@ static int efx_probe_interrupts(struct efx_nic *efx) ...@@ -1191,22 +1262,23 @@ static int efx_probe_interrupts(struct efx_nic *efx)
if (rc == 0) { if (rc == 0) {
efx->n_channels = n_channels; efx->n_channels = n_channels;
if (n_channels > extra_channels)
n_channels -= extra_channels;
if (separate_tx_channels) { if (separate_tx_channels) {
efx->n_tx_channels = efx->n_tx_channels = max(n_channels / 2, 1U);
max(efx->n_channels / 2, 1U); efx->n_rx_channels = max(n_channels -
efx->n_rx_channels = efx->n_tx_channels,
max(efx->n_channels - 1U);
efx->n_tx_channels, 1U);
} else { } else {
efx->n_tx_channels = efx->n_channels; efx->n_tx_channels = n_channels;
efx->n_rx_channels = efx->n_channels; efx->n_rx_channels = n_channels;
} }
rc = efx_init_rx_cpu_rmap(efx, xentries); rc = efx_init_rx_cpu_rmap(efx, xentries);
if (rc) { if (rc) {
pci_disable_msix(efx->pci_dev); pci_disable_msix(efx->pci_dev);
return rc; return rc;
} }
for (i = 0; i < n_channels; i++) for (i = 0; i < efx->n_channels; i++)
efx_get_channel(efx, i)->irq = efx_get_channel(efx, i)->irq =
xentries[i].vector; xentries[i].vector;
} else { } else {
...@@ -1240,11 +1312,26 @@ static int efx_probe_interrupts(struct efx_nic *efx) ...@@ -1240,11 +1312,26 @@ static int efx_probe_interrupts(struct efx_nic *efx)
efx->legacy_irq = efx->pci_dev->irq; 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];
}
}
return 0; return 0;
} }
/* Enable interrupts, then probe and start the event queues */ /* Enable interrupts, then probe and start the event queues */
static void efx_start_interrupts(struct efx_nic *efx) static void efx_start_interrupts(struct efx_nic *efx, bool may_keep_eventq)
{ {
struct efx_channel *channel; struct efx_channel *channel;
...@@ -1253,14 +1340,15 @@ static void efx_start_interrupts(struct efx_nic *efx) ...@@ -1253,14 +1340,15 @@ static void efx_start_interrupts(struct efx_nic *efx)
efx_nic_enable_interrupts(efx); efx_nic_enable_interrupts(efx);
efx_for_each_channel(channel, efx) { efx_for_each_channel(channel, efx) {
efx_init_eventq(channel); if (!channel->type->keep_eventq || !may_keep_eventq)
efx_init_eventq(channel);
efx_start_eventq(channel); efx_start_eventq(channel);
} }
efx_mcdi_mode_event(efx); efx_mcdi_mode_event(efx);
} }
static void efx_stop_interrupts(struct efx_nic *efx) static void efx_stop_interrupts(struct efx_nic *efx, bool may_keep_eventq)
{ {
struct efx_channel *channel; struct efx_channel *channel;
...@@ -1277,7 +1365,8 @@ static void efx_stop_interrupts(struct efx_nic *efx) ...@@ -1277,7 +1365,8 @@ static void efx_stop_interrupts(struct efx_nic *efx)
synchronize_irq(channel->irq); synchronize_irq(channel->irq);
efx_stop_eventq(channel); efx_stop_eventq(channel);
efx_fini_eventq(channel); if (!channel->type->keep_eventq || !may_keep_eventq)
efx_fini_eventq(channel);
} }
} }
...@@ -1383,21 +1472,22 @@ static int efx_probe_all(struct efx_nic *efx) ...@@ -1383,21 +1472,22 @@ static int efx_probe_all(struct efx_nic *efx)
} }
efx->rxq_entries = efx->txq_entries = EFX_DEFAULT_DMAQ_SIZE; efx->rxq_entries = efx->txq_entries = EFX_DEFAULT_DMAQ_SIZE;
rc = efx_probe_channels(efx);
if (rc)
goto fail3;
rc = efx_probe_filters(efx); rc = efx_probe_filters(efx);
if (rc) { if (rc) {
netif_err(efx, probe, efx->net_dev, netif_err(efx, probe, efx->net_dev,
"failed to create filter tables\n"); "failed to create filter tables\n");
goto fail4; goto fail3;
} }
rc = efx_probe_channels(efx);
if (rc)
goto fail4;
return 0; return 0;
fail4: fail4:
efx_remove_channels(efx); efx_remove_filters(efx);
fail3: fail3:
efx_remove_port(efx); efx_remove_port(efx);
fail2: fail2:
...@@ -1482,8 +1572,8 @@ static void efx_stop_all(struct efx_nic *efx) ...@@ -1482,8 +1572,8 @@ static void efx_stop_all(struct efx_nic *efx)
static void efx_remove_all(struct efx_nic *efx) static void efx_remove_all(struct efx_nic *efx)
{ {
efx_remove_filters(efx);
efx_remove_channels(efx); efx_remove_channels(efx);
efx_remove_filters(efx);
efx_remove_port(efx); efx_remove_port(efx);
efx_remove_nic(efx); efx_remove_nic(efx);
} }
...@@ -1627,15 +1717,21 @@ static int efx_ioctl(struct net_device *net_dev, struct ifreq *ifr, int cmd) ...@@ -1627,15 +1717,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) static void efx_init_napi(struct efx_nic *efx)
{ {
struct efx_channel *channel; struct efx_channel *channel;
efx_for_each_channel(channel, efx) { efx_for_each_channel(channel, efx)
channel->napi_dev = efx->net_dev; efx_init_napi_channel(channel);
netif_napi_add(channel->napi_dev, &channel->napi_str,
efx_poll, napi_weight);
}
} }
static void efx_fini_napi_channel(struct efx_channel *channel) static void efx_fini_napi_channel(struct efx_channel *channel)
...@@ -2013,7 +2109,7 @@ void efx_reset_down(struct efx_nic *efx, enum reset_type method) ...@@ -2013,7 +2109,7 @@ void efx_reset_down(struct efx_nic *efx, enum reset_type method)
efx_stop_all(efx); efx_stop_all(efx);
mutex_lock(&efx->mac_lock); mutex_lock(&efx->mac_lock);
efx_stop_interrupts(efx); efx_stop_interrupts(efx, false);
if (efx->port_initialized && method != RESET_TYPE_INVISIBLE) if (efx->port_initialized && method != RESET_TYPE_INVISIBLE)
efx->phy_op->fini(efx); efx->phy_op->fini(efx);
efx->type->fini(efx); efx->type->fini(efx);
...@@ -2050,7 +2146,7 @@ int efx_reset_up(struct efx_nic *efx, enum reset_type method, bool ok) ...@@ -2050,7 +2146,7 @@ int efx_reset_up(struct efx_nic *efx, enum reset_type method, bool ok)
efx->type->reconfigure_mac(efx); efx->type->reconfigure_mac(efx);
efx_start_interrupts(efx); efx_start_interrupts(efx, false);
efx_restore_filters(efx); efx_restore_filters(efx);
mutex_unlock(&efx->mac_lock); mutex_unlock(&efx->mac_lock);
...@@ -2314,7 +2410,7 @@ static void efx_pci_remove_main(struct efx_nic *efx) ...@@ -2314,7 +2410,7 @@ static void efx_pci_remove_main(struct efx_nic *efx)
free_irq_cpu_rmap(efx->net_dev->rx_cpu_rmap); free_irq_cpu_rmap(efx->net_dev->rx_cpu_rmap);
efx->net_dev->rx_cpu_rmap = NULL; efx->net_dev->rx_cpu_rmap = NULL;
#endif #endif
efx_stop_interrupts(efx); efx_stop_interrupts(efx, false);
efx_nic_fini_interrupt(efx); efx_nic_fini_interrupt(efx);
efx_fini_port(efx); efx_fini_port(efx);
efx->type->fini(efx); efx->type->fini(efx);
...@@ -2341,7 +2437,7 @@ static void efx_pci_remove(struct pci_dev *pci_dev) ...@@ -2341,7 +2437,7 @@ static void efx_pci_remove(struct pci_dev *pci_dev)
/* Allow any queued efx_resets() to complete */ /* Allow any queued efx_resets() to complete */
rtnl_unlock(); rtnl_unlock();
efx_stop_interrupts(efx); efx_stop_interrupts(efx, false);
efx_unregister_netdev(efx); efx_unregister_netdev(efx);
efx_mtd_remove(efx); efx_mtd_remove(efx);
...@@ -2393,7 +2489,7 @@ static int efx_pci_probe_main(struct efx_nic *efx) ...@@ -2393,7 +2489,7 @@ static int efx_pci_probe_main(struct efx_nic *efx)
rc = efx_nic_init_interrupt(efx); rc = efx_nic_init_interrupt(efx);
if (rc) if (rc)
goto fail5; goto fail5;
efx_start_interrupts(efx); efx_start_interrupts(efx, false);
return 0; return 0;
...@@ -2517,7 +2613,7 @@ static int efx_pm_freeze(struct device *dev) ...@@ -2517,7 +2613,7 @@ static int efx_pm_freeze(struct device *dev)
netif_device_detach(efx->net_dev); netif_device_detach(efx->net_dev);
efx_stop_all(efx); efx_stop_all(efx);
efx_stop_interrupts(efx); efx_stop_interrupts(efx, false);
return 0; return 0;
} }
...@@ -2528,7 +2624,7 @@ static int efx_pm_thaw(struct device *dev) ...@@ -2528,7 +2624,7 @@ static int efx_pm_thaw(struct device *dev)
efx->state = STATE_INIT; efx->state = STATE_INIT;
efx_start_interrupts(efx); efx_start_interrupts(efx, false);
mutex_lock(&efx->mac_lock); mutex_lock(&efx->mac_lock);
efx->phy_op->reconfigure(efx); efx->phy_op->reconfigure(efx);
......
...@@ -95,6 +95,7 @@ static inline void efx_filter_rfs_expire(struct efx_channel *channel) {} ...@@ -95,6 +95,7 @@ static inline void efx_filter_rfs_expire(struct efx_channel *channel) {}
#endif #endif
/* Channels */ /* Channels */
extern int efx_channel_dummy_op_int(struct efx_channel *channel);
extern void efx_process_channel_now(struct efx_channel *channel); extern void efx_process_channel_now(struct efx_channel *channel);
extern int extern int
efx_realloc_channels(struct efx_nic *efx, u32 rxq_entries, u32 txq_entries); efx_realloc_channels(struct efx_nic *efx, u32 rxq_entries, u32 txq_entries);
......
...@@ -54,6 +54,7 @@ ...@@ -54,6 +54,7 @@
#define EFX_MAX_CHANNELS 32U #define EFX_MAX_CHANNELS 32U
#define EFX_MAX_RX_QUEUES EFX_MAX_CHANNELS #define EFX_MAX_RX_QUEUES EFX_MAX_CHANNELS
#define EFX_MAX_EXTRA_CHANNELS 0U
/* Checksum generation is a per-queue option in hardware, so each /* Checksum generation is a per-queue option in hardware, so each
* queue visible to the networking core is backed by two hardware TX * queue visible to the networking core is backed by two hardware TX
...@@ -311,6 +312,7 @@ enum efx_rx_alloc_method { ...@@ -311,6 +312,7 @@ enum efx_rx_alloc_method {
* *
* @efx: Associated Efx NIC * @efx: Associated Efx NIC
* @channel: Channel instance number * @channel: Channel instance number
* @type: Channel type definition
* @enabled: Channel enabled indicator * @enabled: Channel enabled indicator
* @irq: IRQ number (MSI and MSI-X only) * @irq: IRQ number (MSI and MSI-X only)
* @irq_moderation: IRQ moderation value (in hardware ticks) * @irq_moderation: IRQ moderation value (in hardware ticks)
...@@ -341,6 +343,7 @@ enum efx_rx_alloc_method { ...@@ -341,6 +343,7 @@ enum efx_rx_alloc_method {
struct efx_channel { struct efx_channel {
struct efx_nic *efx; struct efx_nic *efx;
int channel; int channel;
const struct efx_channel_type *type;
bool enabled; bool enabled;
int irq; int irq;
unsigned int irq_moderation; unsigned int irq_moderation;
...@@ -379,6 +382,26 @@ struct efx_channel { ...@@ -379,6 +382,26 @@ struct efx_channel {
struct efx_tx_queue tx_queue[EFX_TXQ_TYPES]; 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 { enum efx_led_mode {
EFX_LED_OFF = 0, EFX_LED_OFF = 0,
EFX_LED_ON = 1, EFX_LED_ON = 1,
...@@ -631,6 +654,8 @@ struct efx_filter_state; ...@@ -631,6 +654,8 @@ struct efx_filter_state;
* @rx_queue: RX DMA queues * @rx_queue: RX DMA queues
* @channel: Channels * @channel: Channels
* @channel_name: Names for channels and their IRQs * @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. * @rxq_entries: Size of receive queues requested by user.
* @txq_entries: Size of transmit queues requested by user. * @txq_entries: Size of transmit queues requested by user.
* @next_buffer_table: First available buffer table id * @next_buffer_table: First available buffer table id
...@@ -723,6 +748,8 @@ struct efx_nic { ...@@ -723,6 +748,8 @@ struct efx_nic {
struct efx_channel *channel[EFX_MAX_CHANNELS]; struct efx_channel *channel[EFX_MAX_CHANNELS];
char channel_name[EFX_MAX_CHANNELS][IFNAMSIZ + 6]; char channel_name[EFX_MAX_CHANNELS][IFNAMSIZ + 6];
const struct efx_channel_type *
extra_channel_type[EFX_MAX_EXTRA_CHANNELS];
unsigned rxq_entries; unsigned rxq_entries;
unsigned txq_entries; unsigned txq_entries;
...@@ -921,6 +948,13 @@ efx_get_channel(struct efx_nic *efx, unsigned index) ...@@ -921,6 +948,13 @@ efx_get_channel(struct efx_nic *efx, unsigned index)
_channel = (_channel->channel + 1 < (_efx)->n_channels) ? \ _channel = (_channel->channel + 1 < (_efx)->n_channels) ? \
(_efx)->channel[_channel->channel + 1] : NULL) (_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 * static inline struct efx_tx_queue *
efx_get_tx_queue(struct efx_nic *efx, unsigned index, unsigned type) efx_get_tx_queue(struct efx_nic *efx, unsigned index, unsigned type)
{ {
......
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