sfc: Allocate each channel separately, along with its RX and TX queues
This will allow for reallocation of channel structures and rings. Change module parameter separate_tx_channels to be read-only, since we now require its value to be constant. Signed-off-by: Ben Hutchings <bhutchings@solarflare.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
f7d12cdcbb
commit
8313aca38b
3 changed files with 61 additions and 76 deletions
|
@ -114,7 +114,7 @@ static struct workqueue_struct *reset_workqueue;
|
||||||
* This is only used in MSI-X interrupt mode
|
* This is only used in MSI-X interrupt mode
|
||||||
*/
|
*/
|
||||||
static unsigned int separate_tx_channels;
|
static unsigned int separate_tx_channels;
|
||||||
module_param(separate_tx_channels, uint, 0644);
|
module_param(separate_tx_channels, uint, 0444);
|
||||||
MODULE_PARM_DESC(separate_tx_channels,
|
MODULE_PARM_DESC(separate_tx_channels,
|
||||||
"Use separate channels for TX and RX");
|
"Use separate channels for TX and RX");
|
||||||
|
|
||||||
|
@ -334,6 +334,7 @@ void efx_process_channel_now(struct efx_channel *channel)
|
||||||
{
|
{
|
||||||
struct efx_nic *efx = channel->efx;
|
struct efx_nic *efx = channel->efx;
|
||||||
|
|
||||||
|
BUG_ON(channel->channel >= efx->n_channels);
|
||||||
BUG_ON(!channel->enabled);
|
BUG_ON(!channel->enabled);
|
||||||
|
|
||||||
/* Disable interrupts and wait for ISRs to complete */
|
/* Disable interrupts and wait for ISRs to complete */
|
||||||
|
@ -1098,26 +1099,32 @@ static void efx_remove_interrupts(struct efx_nic *efx)
|
||||||
efx->legacy_irq = 0;
|
efx->legacy_irq = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct efx_tx_queue *
|
||||||
|
efx_get_tx_queue(struct efx_nic *efx, unsigned index, unsigned type)
|
||||||
|
{
|
||||||
|
unsigned tx_channel_offset =
|
||||||
|
separate_tx_channels ? efx->n_channels - efx->n_tx_channels : 0;
|
||||||
|
EFX_BUG_ON_PARANOID(index >= efx->n_tx_channels ||
|
||||||
|
type >= EFX_TXQ_TYPES);
|
||||||
|
return &efx->channel[tx_channel_offset + index]->tx_queue[type];
|
||||||
|
}
|
||||||
|
|
||||||
static void efx_set_channels(struct efx_nic *efx)
|
static void efx_set_channels(struct efx_nic *efx)
|
||||||
{
|
{
|
||||||
struct efx_channel *channel;
|
struct efx_channel *channel;
|
||||||
struct efx_tx_queue *tx_queue;
|
struct efx_tx_queue *tx_queue;
|
||||||
struct efx_rx_queue *rx_queue;
|
|
||||||
unsigned tx_channel_offset =
|
unsigned tx_channel_offset =
|
||||||
separate_tx_channels ? efx->n_channels - efx->n_tx_channels : 0;
|
separate_tx_channels ? efx->n_channels - efx->n_tx_channels : 0;
|
||||||
|
|
||||||
|
/* Channel pointers were set in efx_init_struct() but we now
|
||||||
|
* need to clear them for TX queues in any RX-only channels. */
|
||||||
efx_for_each_channel(channel, efx) {
|
efx_for_each_channel(channel, efx) {
|
||||||
if (channel->channel - tx_channel_offset < efx->n_tx_channels) {
|
if (channel->channel - tx_channel_offset >=
|
||||||
channel->tx_queue = &efx->tx_queue[
|
efx->n_tx_channels) {
|
||||||
(channel->channel - tx_channel_offset) *
|
|
||||||
EFX_TXQ_TYPES];
|
|
||||||
efx_for_each_channel_tx_queue(tx_queue, channel)
|
efx_for_each_channel_tx_queue(tx_queue, channel)
|
||||||
tx_queue->channel = channel;
|
tx_queue->channel = NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
efx_for_each_rx_queue(rx_queue, efx)
|
|
||||||
rx_queue->channel = &efx->channel[rx_queue->queue];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int efx_probe_nic(struct efx_nic *efx)
|
static int efx_probe_nic(struct efx_nic *efx)
|
||||||
|
@ -2044,7 +2051,7 @@ static int efx_init_struct(struct efx_nic *efx, struct efx_nic_type *type,
|
||||||
struct efx_channel *channel;
|
struct efx_channel *channel;
|
||||||
struct efx_tx_queue *tx_queue;
|
struct efx_tx_queue *tx_queue;
|
||||||
struct efx_rx_queue *rx_queue;
|
struct efx_rx_queue *rx_queue;
|
||||||
int i;
|
int i, j;
|
||||||
|
|
||||||
/* Initialise common structures */
|
/* Initialise common structures */
|
||||||
memset(efx, 0, sizeof(*efx));
|
memset(efx, 0, sizeof(*efx));
|
||||||
|
@ -2072,27 +2079,22 @@ static int efx_init_struct(struct efx_nic *efx, struct efx_nic_type *type,
|
||||||
INIT_WORK(&efx->mac_work, efx_mac_work);
|
INIT_WORK(&efx->mac_work, efx_mac_work);
|
||||||
|
|
||||||
for (i = 0; i < EFX_MAX_CHANNELS; i++) {
|
for (i = 0; i < EFX_MAX_CHANNELS; i++) {
|
||||||
channel = &efx->channel[i];
|
efx->channel[i] = kzalloc(sizeof(*channel), GFP_KERNEL);
|
||||||
|
channel = efx->channel[i];
|
||||||
channel->efx = efx;
|
channel->efx = efx;
|
||||||
channel->channel = i;
|
channel->channel = i;
|
||||||
channel->work_pending = false;
|
|
||||||
spin_lock_init(&channel->tx_stop_lock);
|
spin_lock_init(&channel->tx_stop_lock);
|
||||||
atomic_set(&channel->tx_stop_count, 1);
|
atomic_set(&channel->tx_stop_count, 1);
|
||||||
}
|
|
||||||
for (i = 0; i < EFX_MAX_TX_QUEUES; i++) {
|
for (j = 0; j < EFX_TXQ_TYPES; j++) {
|
||||||
tx_queue = &efx->tx_queue[i];
|
tx_queue = &channel->tx_queue[j];
|
||||||
tx_queue->efx = efx;
|
tx_queue->efx = efx;
|
||||||
tx_queue->queue = i;
|
tx_queue->queue = i * EFX_TXQ_TYPES + j;
|
||||||
tx_queue->buffer = NULL;
|
tx_queue->channel = channel;
|
||||||
tx_queue->channel = &efx->channel[0]; /* for safety */
|
}
|
||||||
tx_queue->tso_headers_free = NULL;
|
|
||||||
}
|
rx_queue = &channel->rx_queue;
|
||||||
for (i = 0; i < EFX_MAX_RX_QUEUES; i++) {
|
|
||||||
rx_queue = &efx->rx_queue[i];
|
|
||||||
rx_queue->efx = efx;
|
rx_queue->efx = efx;
|
||||||
rx_queue->queue = i;
|
|
||||||
rx_queue->channel = &efx->channel[0]; /* for safety */
|
|
||||||
rx_queue->buffer = NULL;
|
|
||||||
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);
|
||||||
}
|
}
|
||||||
|
@ -2120,6 +2122,11 @@ static int efx_init_struct(struct efx_nic *efx, struct efx_nic_type *type,
|
||||||
|
|
||||||
static void efx_fini_struct(struct efx_nic *efx)
|
static void efx_fini_struct(struct efx_nic *efx)
|
||||||
{
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < EFX_MAX_CHANNELS; i++)
|
||||||
|
kfree(efx->channel[i]);
|
||||||
|
|
||||||
if (efx->workqueue) {
|
if (efx->workqueue) {
|
||||||
destroy_workqueue(efx->workqueue);
|
destroy_workqueue(efx->workqueue);
|
||||||
efx->workqueue = NULL;
|
efx->workqueue = NULL;
|
||||||
|
|
|
@ -159,7 +159,6 @@ irqreturn_t falcon_legacy_interrupt_a1(int irq, void *dev_id)
|
||||||
{
|
{
|
||||||
struct efx_nic *efx = dev_id;
|
struct efx_nic *efx = dev_id;
|
||||||
efx_oword_t *int_ker = efx->irq_status.addr;
|
efx_oword_t *int_ker = efx->irq_status.addr;
|
||||||
struct efx_channel *channel;
|
|
||||||
int syserr;
|
int syserr;
|
||||||
int queues;
|
int queues;
|
||||||
|
|
||||||
|
@ -194,15 +193,10 @@ irqreturn_t falcon_legacy_interrupt_a1(int irq, void *dev_id)
|
||||||
wmb(); /* Ensure the vector is cleared before interrupt ack */
|
wmb(); /* Ensure the vector is cleared before interrupt ack */
|
||||||
falcon_irq_ack_a1(efx);
|
falcon_irq_ack_a1(efx);
|
||||||
|
|
||||||
/* Schedule processing of any interrupting queues */
|
if (queues & 1)
|
||||||
channel = &efx->channel[0];
|
efx_schedule_channel(efx_get_channel(efx, 0));
|
||||||
while (queues) {
|
if (queues & 2)
|
||||||
if (queues & 0x01)
|
efx_schedule_channel(efx_get_channel(efx, 1));
|
||||||
efx_schedule_channel(channel);
|
|
||||||
channel++;
|
|
||||||
queues >>= 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return IRQ_HANDLED;
|
return IRQ_HANDLED;
|
||||||
}
|
}
|
||||||
/**************************************************************************
|
/**************************************************************************
|
||||||
|
|
|
@ -225,8 +225,6 @@ struct efx_rx_page_state {
|
||||||
/**
|
/**
|
||||||
* struct efx_rx_queue - An Efx RX queue
|
* struct efx_rx_queue - An Efx RX queue
|
||||||
* @efx: The associated Efx NIC
|
* @efx: The associated Efx NIC
|
||||||
* @queue: DMA queue number
|
|
||||||
* @channel: The associated channel
|
|
||||||
* @buffer: The software buffer ring
|
* @buffer: The software buffer ring
|
||||||
* @rxd: The hardware descriptor ring
|
* @rxd: The hardware descriptor ring
|
||||||
* @added_count: Number of buffers added to the receive queue.
|
* @added_count: Number of buffers added to the receive queue.
|
||||||
|
@ -250,8 +248,6 @@ struct efx_rx_page_state {
|
||||||
*/
|
*/
|
||||||
struct efx_rx_queue {
|
struct efx_rx_queue {
|
||||||
struct efx_nic *efx;
|
struct efx_nic *efx;
|
||||||
int queue;
|
|
||||||
struct efx_channel *channel;
|
|
||||||
struct efx_rx_buffer *buffer;
|
struct efx_rx_buffer *buffer;
|
||||||
struct efx_special_buffer rxd;
|
struct efx_special_buffer rxd;
|
||||||
|
|
||||||
|
@ -327,9 +323,10 @@ enum efx_rx_alloc_method {
|
||||||
* @n_rx_frm_trunc: Count of RX_FRM_TRUNC errors
|
* @n_rx_frm_trunc: Count of RX_FRM_TRUNC errors
|
||||||
* @n_rx_overlength: Count of RX_OVERLENGTH errors
|
* @n_rx_overlength: Count of RX_OVERLENGTH errors
|
||||||
* @n_skbuff_leaks: Count of skbuffs leaked due to RX overrun
|
* @n_skbuff_leaks: Count of skbuffs leaked due to RX overrun
|
||||||
* @tx_queue: Pointer to first TX queue, or %NULL if not used for TX
|
* @rx_queue: RX queue for this channel
|
||||||
* @tx_stop_count: Core TX queue stop count
|
* @tx_stop_count: Core TX queue stop count
|
||||||
* @tx_stop_lock: Core TX queue stop lock
|
* @tx_stop_lock: Core TX queue stop lock
|
||||||
|
* @tx_queue: TX queues for this channel
|
||||||
*/
|
*/
|
||||||
struct efx_channel {
|
struct efx_channel {
|
||||||
struct efx_nic *efx;
|
struct efx_nic *efx;
|
||||||
|
@ -366,9 +363,12 @@ struct efx_channel {
|
||||||
struct efx_rx_buffer *rx_pkt;
|
struct efx_rx_buffer *rx_pkt;
|
||||||
bool rx_pkt_csummed;
|
bool rx_pkt_csummed;
|
||||||
|
|
||||||
struct efx_tx_queue *tx_queue;
|
struct efx_rx_queue rx_queue;
|
||||||
|
|
||||||
atomic_t tx_stop_count;
|
atomic_t tx_stop_count;
|
||||||
spinlock_t tx_stop_lock;
|
spinlock_t tx_stop_lock;
|
||||||
|
|
||||||
|
struct efx_tx_queue tx_queue[2];
|
||||||
};
|
};
|
||||||
|
|
||||||
enum efx_led_mode {
|
enum efx_led_mode {
|
||||||
|
@ -724,9 +724,7 @@ struct efx_nic {
|
||||||
enum nic_state state;
|
enum nic_state state;
|
||||||
enum reset_type reset_pending;
|
enum reset_type reset_pending;
|
||||||
|
|
||||||
struct efx_tx_queue tx_queue[EFX_MAX_TX_QUEUES];
|
struct efx_channel *channel[EFX_MAX_CHANNELS];
|
||||||
struct efx_rx_queue rx_queue[EFX_MAX_RX_QUEUES];
|
|
||||||
struct efx_channel channel[EFX_MAX_CHANNELS];
|
|
||||||
|
|
||||||
unsigned next_buffer_table;
|
unsigned next_buffer_table;
|
||||||
unsigned n_channels;
|
unsigned n_channels;
|
||||||
|
@ -913,34 +911,30 @@ static inline struct efx_channel *
|
||||||
efx_get_channel(struct efx_nic *efx, unsigned index)
|
efx_get_channel(struct efx_nic *efx, unsigned index)
|
||||||
{
|
{
|
||||||
EFX_BUG_ON_PARANOID(index >= efx->n_channels);
|
EFX_BUG_ON_PARANOID(index >= efx->n_channels);
|
||||||
return &efx->channel[index];
|
return efx->channel[index];
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Iterate over all used channels */
|
/* Iterate over all used channels */
|
||||||
#define efx_for_each_channel(_channel, _efx) \
|
#define efx_for_each_channel(_channel, _efx) \
|
||||||
for (_channel = &((_efx)->channel[0]); \
|
for (_channel = (_efx)->channel[0]; \
|
||||||
_channel < &((_efx)->channel[(efx)->n_channels]); \
|
_channel; \
|
||||||
_channel++)
|
_channel = (_channel->channel + 1 < (_efx)->n_channels) ? \
|
||||||
|
(_efx)->channel[_channel->channel + 1] : NULL)
|
||||||
|
|
||||||
static inline struct efx_tx_queue *
|
extern 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);
|
||||||
{
|
|
||||||
EFX_BUG_ON_PARANOID(index >= efx->n_tx_channels ||
|
|
||||||
type >= EFX_TXQ_TYPES);
|
|
||||||
return &efx->tx_queue[index * EFX_TXQ_TYPES + type];
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline struct efx_tx_queue *
|
static inline struct efx_tx_queue *
|
||||||
efx_channel_get_tx_queue(struct efx_channel *channel, unsigned type)
|
efx_channel_get_tx_queue(struct efx_channel *channel, unsigned type)
|
||||||
{
|
{
|
||||||
struct efx_tx_queue *tx_queue = channel->tx_queue;
|
struct efx_tx_queue *tx_queue = channel->tx_queue;
|
||||||
EFX_BUG_ON_PARANOID(type >= EFX_TXQ_TYPES);
|
EFX_BUG_ON_PARANOID(type >= EFX_TXQ_TYPES);
|
||||||
return tx_queue ? tx_queue + type : NULL;
|
return tx_queue->channel ? tx_queue + type : NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Iterate over all TX queues belonging to a channel */
|
/* Iterate over all TX queues belonging to a channel */
|
||||||
#define efx_for_each_channel_tx_queue(_tx_queue, _channel) \
|
#define efx_for_each_channel_tx_queue(_tx_queue, _channel) \
|
||||||
for (_tx_queue = (_channel)->tx_queue; \
|
for (_tx_queue = efx_channel_get_tx_queue(channel, 0); \
|
||||||
_tx_queue && _tx_queue < (_channel)->tx_queue + EFX_TXQ_TYPES; \
|
_tx_queue && _tx_queue < (_channel)->tx_queue + EFX_TXQ_TYPES; \
|
||||||
_tx_queue++)
|
_tx_queue++)
|
||||||
|
|
||||||
|
@ -948,41 +942,31 @@ static inline struct efx_rx_queue *
|
||||||
efx_get_rx_queue(struct efx_nic *efx, unsigned index)
|
efx_get_rx_queue(struct efx_nic *efx, unsigned index)
|
||||||
{
|
{
|
||||||
EFX_BUG_ON_PARANOID(index >= efx->n_rx_channels);
|
EFX_BUG_ON_PARANOID(index >= efx->n_rx_channels);
|
||||||
return &efx->rx_queue[index];
|
return &efx->channel[index]->rx_queue;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Iterate over all used RX queues */
|
|
||||||
#define efx_for_each_rx_queue(_rx_queue, _efx) \
|
|
||||||
for (_rx_queue = &((_efx)->rx_queue[0]); \
|
|
||||||
_rx_queue < &((_efx)->rx_queue[(_efx)->n_rx_channels]); \
|
|
||||||
_rx_queue++)
|
|
||||||
|
|
||||||
static inline struct efx_rx_queue *
|
static inline struct efx_rx_queue *
|
||||||
efx_channel_get_rx_queue(struct efx_channel *channel)
|
efx_channel_get_rx_queue(struct efx_channel *channel)
|
||||||
{
|
{
|
||||||
struct efx_rx_queue *rx_queue =
|
return channel->channel < channel->efx->n_rx_channels ?
|
||||||
&channel->efx->rx_queue[channel->channel];
|
&channel->rx_queue : NULL;
|
||||||
return rx_queue->channel == channel ? rx_queue : NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Iterate over all RX queues belonging to a channel */
|
/* Iterate over all RX queues belonging to a channel */
|
||||||
#define efx_for_each_channel_rx_queue(_rx_queue, _channel) \
|
#define efx_for_each_channel_rx_queue(_rx_queue, _channel) \
|
||||||
for (_rx_queue = &((_channel)->efx->rx_queue[(_channel)->channel]); \
|
for (_rx_queue = efx_channel_get_rx_queue(channel); \
|
||||||
_rx_queue; \
|
_rx_queue; \
|
||||||
_rx_queue = NULL) \
|
_rx_queue = NULL)
|
||||||
if (_rx_queue->channel != (_channel)) \
|
|
||||||
continue; \
|
|
||||||
else
|
|
||||||
|
|
||||||
static inline struct efx_channel *
|
static inline struct efx_channel *
|
||||||
efx_rx_queue_channel(struct efx_rx_queue *rx_queue)
|
efx_rx_queue_channel(struct efx_rx_queue *rx_queue)
|
||||||
{
|
{
|
||||||
return rx_queue->channel;
|
return container_of(rx_queue, struct efx_channel, rx_queue);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline int efx_rx_queue_index(struct efx_rx_queue *rx_queue)
|
static inline int efx_rx_queue_index(struct efx_rx_queue *rx_queue)
|
||||||
{
|
{
|
||||||
return rx_queue->queue;
|
return efx_rx_queue_channel(rx_queue)->channel;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Returns a pointer to the specified receive buffer in the RX
|
/* Returns a pointer to the specified receive buffer in the RX
|
||||||
|
|
Loading…
Reference in a new issue