sfc: Rework IRQ enable/disable
There are many problems with the current efx_stop_interrupts() and efx_start_interrupts(): 1. On Siena, it is unsafe to disable the master IRQ enable bit (DRV_INT_EN_KER) while any IRQ sources are enabled. 2. On EF10 there is no master IRQ enable bit, so we cannot expect to defer IRQs without tearing down event queues. (Though I don't think we will need to keep any event queues around while the device is down, as we do for VFDI on Siena.) 3. synchronize_irq() only waits for a running IRQ handler to finish, not for any propagation through IRQ controllers. Therefore an IRQ may still be received and handled after efx_stop_interrupts() returns. IRQ handlers can then race with channel reallocation. To fix this: a. Introduce a software IRQ enable flag. So long as this is clear, IRQ handlers will only acknowledge IRQs and not touch the channel structures. b. Define a new struct efx_msi_context as the context for MSIs. This is never reallocated and is sufficient to find the software enable flag and the channel structure. It also includes the channel/IRQ name, which was previously separated out as it must also not be reallocated. c. Split efx_{start,stop}_interrupts() into efx_{,soft_}_{enable,disable}_interrupts(). The 'soft' functions don't touch the hardware master enable flag (if it exists) and don't reinitialise or tear down channels with the keep_eventq flag set. Signed-off-by: Ben Hutchings <bhutchings@solarflare.com>
This commit is contained in:
parent
514bedbc3a
commit
d829118705
4 changed files with 119 additions and 66 deletions
|
@ -419,6 +419,21 @@ struct efx_channel {
|
|||
struct efx_tx_queue tx_queue[EFX_TXQ_TYPES];
|
||||
};
|
||||
|
||||
/**
|
||||
* struct efx_msi_context - Context for each MSI
|
||||
* @efx: The associated NIC
|
||||
* @index: Index of the channel/IRQ
|
||||
* @name: Name of the channel/IRQ
|
||||
*
|
||||
* Unlike &struct efx_channel, this is never reallocated and is always
|
||||
* safe for the IRQ handler to access.
|
||||
*/
|
||||
struct efx_msi_context {
|
||||
struct efx_nic *efx;
|
||||
unsigned int index;
|
||||
char name[IFNAMSIZ + 6];
|
||||
};
|
||||
|
||||
/**
|
||||
* struct efx_channel_type - distinguishes traffic and extra channels
|
||||
* @handle_no_channel: Handle failure to allocate an extra channel
|
||||
|
@ -669,7 +684,6 @@ struct vfdi_status;
|
|||
* @pci_dev: The PCI device
|
||||
* @type: Controller type attributes
|
||||
* @legacy_irq: IRQ number
|
||||
* @legacy_irq_enabled: Are IRQs enabled on NIC (INT_EN_KER register)?
|
||||
* @workqueue: Workqueue for port reconfigures and the HW monitor.
|
||||
* Work items do not hold and must not acquire RTNL.
|
||||
* @workqueue_name: Name of workqueue
|
||||
|
@ -686,7 +700,7 @@ struct vfdi_status;
|
|||
* @tx_queue: TX DMA queues
|
||||
* @rx_queue: RX DMA queues
|
||||
* @channel: Channels
|
||||
* @channel_name: Names for channels and their IRQs
|
||||
* @msi_context: Context for each MSI
|
||||
* @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.
|
||||
|
@ -709,6 +723,8 @@ struct vfdi_status;
|
|||
* @rx_scatter: Scatter mode enabled for receives
|
||||
* @int_error_count: Number of internal errors seen recently
|
||||
* @int_error_expire: Time at which error count will be expired
|
||||
* @irq_soft_enabled: Are IRQs soft-enabled? If not, IRQ handler will
|
||||
* acknowledge but do nothing else.
|
||||
* @irq_status: Interrupt status buffer
|
||||
* @irq_zero_count: Number of legacy IRQs seen with queue flags == 0
|
||||
* @irq_level: IRQ level/index for IRQs not triggered by an event queue
|
||||
|
@ -786,7 +802,6 @@ struct efx_nic {
|
|||
unsigned int port_num;
|
||||
const struct efx_nic_type *type;
|
||||
int legacy_irq;
|
||||
bool legacy_irq_enabled;
|
||||
bool eeh_disabled_legacy_irq;
|
||||
struct workqueue_struct *workqueue;
|
||||
char workqueue_name[16];
|
||||
|
@ -804,7 +819,7 @@ struct efx_nic {
|
|||
unsigned long reset_pending;
|
||||
|
||||
struct efx_channel *channel[EFX_MAX_CHANNELS];
|
||||
char channel_name[EFX_MAX_CHANNELS][IFNAMSIZ + 6];
|
||||
struct efx_msi_context msi_context[EFX_MAX_CHANNELS];
|
||||
const struct efx_channel_type *
|
||||
extra_channel_type[EFX_MAX_EXTRA_CHANNELS];
|
||||
|
||||
|
@ -835,6 +850,7 @@ struct efx_nic {
|
|||
unsigned int_error_count;
|
||||
unsigned long int_error_expire;
|
||||
|
||||
bool irq_soft_enabled;
|
||||
struct efx_buffer irq_status;
|
||||
unsigned irq_zero_count;
|
||||
unsigned irq_level;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue