sfc: Move and rename Falcon/Siena common NIC operations
Add efx_nic_type operations for the many efx_nic functions that need to be implemented different on EF10. For now, change most of the existing efx_nic_*() functions into inline wrappers. As a later step, we may be able to improve branch prediction for operations used on the fast path by copying the pointers into each queue/channel structure. Move the Falcon/Siena implementations to new file farch.c and rename the functions and static data to use a prefix of 'efx_farch_'. Move efx_may_push_tx_desc() to nic.h, as the EF10 TX code will also use it. Signed-off-by: Ben Hutchings <bhutchings@solarflare.com>
This commit is contained in:
@@ -34,7 +34,7 @@ static inline int efx_nic_rev(struct efx_nic *efx)
|
||||
return efx->type->revision;
|
||||
}
|
||||
|
||||
extern u32 efx_nic_fpga_ver(struct efx_nic *efx);
|
||||
extern u32 efx_farch_fpga_ver(struct efx_nic *efx);
|
||||
|
||||
/* NIC has two interlinked PCI functions for the same port. */
|
||||
static inline bool efx_nic_is_dual_func(struct efx_nic *efx)
|
||||
@@ -42,6 +42,65 @@ static inline bool efx_nic_is_dual_func(struct efx_nic *efx)
|
||||
return efx_nic_rev(efx) < EFX_REV_FALCON_B0;
|
||||
}
|
||||
|
||||
/* Read the current event from the event queue */
|
||||
static inline efx_qword_t *efx_event(struct efx_channel *channel,
|
||||
unsigned int index)
|
||||
{
|
||||
return ((efx_qword_t *) (channel->eventq.buf.addr)) +
|
||||
(index & channel->eventq_mask);
|
||||
}
|
||||
|
||||
/* See if an event is present
|
||||
*
|
||||
* We check both the high and low dword of the event for all ones. We
|
||||
* wrote all ones when we cleared the event, and no valid event can
|
||||
* have all ones in either its high or low dwords. This approach is
|
||||
* robust against reordering.
|
||||
*
|
||||
* Note that using a single 64-bit comparison is incorrect; even
|
||||
* though the CPU read will be atomic, the DMA write may not be.
|
||||
*/
|
||||
static inline int efx_event_present(efx_qword_t *event)
|
||||
{
|
||||
return !(EFX_DWORD_IS_ALL_ONES(event->dword[0]) |
|
||||
EFX_DWORD_IS_ALL_ONES(event->dword[1]));
|
||||
}
|
||||
|
||||
/* Returns a pointer to the specified transmit descriptor in the TX
|
||||
* descriptor queue belonging to the specified channel.
|
||||
*/
|
||||
static inline efx_qword_t *
|
||||
efx_tx_desc(struct efx_tx_queue *tx_queue, unsigned int index)
|
||||
{
|
||||
return ((efx_qword_t *) (tx_queue->txd.buf.addr)) + index;
|
||||
}
|
||||
|
||||
/* Decide whether to push a TX descriptor to the NIC vs merely writing
|
||||
* the doorbell. This can reduce latency when we are adding a single
|
||||
* descriptor to an empty queue, but is otherwise pointless. Further,
|
||||
* Falcon and Siena have hardware bugs (SF bug 33851) that may be
|
||||
* triggered if we don't check this.
|
||||
*/
|
||||
static inline bool efx_nic_may_push_tx_desc(struct efx_tx_queue *tx_queue,
|
||||
unsigned int write_count)
|
||||
{
|
||||
unsigned empty_read_count = ACCESS_ONCE(tx_queue->empty_read_count);
|
||||
|
||||
if (empty_read_count == 0)
|
||||
return false;
|
||||
|
||||
tx_queue->empty_read_count = 0;
|
||||
return ((empty_read_count ^ write_count) & ~EFX_EMPTY_COUNT_VALID) == 0
|
||||
&& tx_queue->write_count - write_count == 1;
|
||||
}
|
||||
|
||||
/* Returns a pointer to the specified descriptor in the RX descriptor queue */
|
||||
static inline efx_qword_t *
|
||||
efx_rx_desc(struct efx_rx_queue *rx_queue, unsigned int index)
|
||||
{
|
||||
return ((efx_qword_t *) (rx_queue->rxd.buf.addr)) + index;
|
||||
}
|
||||
|
||||
enum {
|
||||
PHY_TYPE_NONE = 0,
|
||||
PHY_TYPE_TXC43128 = 1,
|
||||
@@ -258,25 +317,93 @@ extern const struct efx_nic_type siena_a0_nic_type;
|
||||
extern int falcon_probe_board(struct efx_nic *efx, u16 revision_info);
|
||||
|
||||
/* TX data path */
|
||||
extern int efx_nic_probe_tx(struct efx_tx_queue *tx_queue);
|
||||
extern void efx_nic_init_tx(struct efx_tx_queue *tx_queue);
|
||||
extern void efx_nic_remove_tx(struct efx_tx_queue *tx_queue);
|
||||
extern void efx_nic_push_buffers(struct efx_tx_queue *tx_queue);
|
||||
static inline int efx_nic_probe_tx(struct efx_tx_queue *tx_queue)
|
||||
{
|
||||
return tx_queue->efx->type->tx_probe(tx_queue);
|
||||
}
|
||||
static inline void efx_nic_init_tx(struct efx_tx_queue *tx_queue)
|
||||
{
|
||||
tx_queue->efx->type->tx_init(tx_queue);
|
||||
}
|
||||
static inline void efx_nic_remove_tx(struct efx_tx_queue *tx_queue)
|
||||
{
|
||||
tx_queue->efx->type->tx_remove(tx_queue);
|
||||
}
|
||||
static inline void efx_nic_push_buffers(struct efx_tx_queue *tx_queue)
|
||||
{
|
||||
tx_queue->efx->type->tx_write(tx_queue);
|
||||
}
|
||||
|
||||
/* RX data path */
|
||||
extern int efx_nic_probe_rx(struct efx_rx_queue *rx_queue);
|
||||
extern void efx_nic_init_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);
|
||||
static inline int efx_nic_probe_rx(struct efx_rx_queue *rx_queue)
|
||||
{
|
||||
return rx_queue->efx->type->rx_probe(rx_queue);
|
||||
}
|
||||
static inline void efx_nic_init_rx(struct efx_rx_queue *rx_queue)
|
||||
{
|
||||
rx_queue->efx->type->rx_init(rx_queue);
|
||||
}
|
||||
static inline void efx_nic_remove_rx(struct efx_rx_queue *rx_queue)
|
||||
{
|
||||
rx_queue->efx->type->rx_remove(rx_queue);
|
||||
}
|
||||
static inline void efx_nic_notify_rx_desc(struct efx_rx_queue *rx_queue)
|
||||
{
|
||||
rx_queue->efx->type->rx_write(rx_queue);
|
||||
}
|
||||
static inline void efx_nic_generate_fill_event(struct efx_rx_queue *rx_queue)
|
||||
{
|
||||
rx_queue->efx->type->rx_defer_refill(rx_queue);
|
||||
}
|
||||
|
||||
/* Event data path */
|
||||
extern int efx_nic_probe_eventq(struct efx_channel *channel);
|
||||
extern void efx_nic_init_eventq(struct efx_channel *channel);
|
||||
extern void efx_nic_fini_eventq(struct efx_channel *channel);
|
||||
extern void efx_nic_remove_eventq(struct efx_channel *channel);
|
||||
extern int efx_nic_process_eventq(struct efx_channel *channel, int rx_quota);
|
||||
extern void efx_nic_eventq_read_ack(struct efx_channel *channel);
|
||||
static inline int efx_nic_probe_eventq(struct efx_channel *channel)
|
||||
{
|
||||
return channel->efx->type->ev_probe(channel);
|
||||
}
|
||||
static inline void efx_nic_init_eventq(struct efx_channel *channel)
|
||||
{
|
||||
channel->efx->type->ev_init(channel);
|
||||
}
|
||||
static inline void efx_nic_fini_eventq(struct efx_channel *channel)
|
||||
{
|
||||
channel->efx->type->ev_fini(channel);
|
||||
}
|
||||
static inline void efx_nic_remove_eventq(struct efx_channel *channel)
|
||||
{
|
||||
channel->efx->type->ev_remove(channel);
|
||||
}
|
||||
static inline int
|
||||
efx_nic_process_eventq(struct efx_channel *channel, int quota)
|
||||
{
|
||||
return channel->efx->type->ev_process(channel, quota);
|
||||
}
|
||||
static inline void efx_nic_eventq_read_ack(struct efx_channel *channel)
|
||||
{
|
||||
channel->efx->type->ev_read_ack(channel);
|
||||
}
|
||||
extern void efx_nic_event_test_start(struct efx_channel *channel);
|
||||
|
||||
/* Falcon/Siena queue operations */
|
||||
extern int efx_farch_tx_probe(struct efx_tx_queue *tx_queue);
|
||||
extern void efx_farch_tx_init(struct efx_tx_queue *tx_queue);
|
||||
extern void efx_farch_tx_fini(struct efx_tx_queue *tx_queue);
|
||||
extern void efx_farch_tx_remove(struct efx_tx_queue *tx_queue);
|
||||
extern void efx_farch_tx_write(struct efx_tx_queue *tx_queue);
|
||||
extern int efx_farch_rx_probe(struct efx_rx_queue *rx_queue);
|
||||
extern void efx_farch_rx_init(struct efx_rx_queue *rx_queue);
|
||||
extern void efx_farch_rx_fini(struct efx_rx_queue *rx_queue);
|
||||
extern void efx_farch_rx_remove(struct efx_rx_queue *rx_queue);
|
||||
extern void efx_farch_rx_write(struct efx_rx_queue *rx_queue);
|
||||
extern void efx_farch_rx_defer_refill(struct efx_rx_queue *rx_queue);
|
||||
extern int efx_farch_ev_probe(struct efx_channel *channel);
|
||||
extern void efx_farch_ev_init(struct efx_channel *channel);
|
||||
extern void efx_farch_ev_fini(struct efx_channel *channel);
|
||||
extern void efx_farch_ev_remove(struct efx_channel *channel);
|
||||
extern int efx_farch_ev_process(struct efx_channel *channel, int quota);
|
||||
extern void efx_farch_ev_read_ack(struct efx_channel *channel);
|
||||
extern void efx_farch_ev_test_generate(struct efx_channel *channel);
|
||||
|
||||
extern bool efx_nic_event_present(struct efx_channel *channel);
|
||||
|
||||
/* Some statistics are computed as A - B where A and B each increase
|
||||
@@ -297,15 +424,18 @@ static inline void efx_update_diff_stat(u64 *stat, u64 diff)
|
||||
*stat = diff;
|
||||
}
|
||||
|
||||
/* Interrupts and test events */
|
||||
/* Interrupts */
|
||||
extern int efx_nic_init_interrupt(struct efx_nic *efx);
|
||||
extern void efx_nic_enable_interrupts(struct efx_nic *efx);
|
||||
extern void efx_nic_event_test_start(struct efx_channel *channel);
|
||||
extern void efx_nic_irq_test_start(struct efx_nic *efx);
|
||||
extern void efx_nic_disable_interrupts(struct efx_nic *efx);
|
||||
extern void efx_nic_fini_interrupt(struct efx_nic *efx);
|
||||
extern irqreturn_t efx_nic_fatal_interrupt(struct efx_nic *efx);
|
||||
extern irqreturn_t falcon_legacy_interrupt_a1(int irq, void *dev_id);
|
||||
|
||||
/* Falcon/Siena interrupts */
|
||||
extern void efx_farch_irq_enable_master(struct efx_nic *efx);
|
||||
extern void efx_farch_irq_test_generate(struct efx_nic *efx);
|
||||
extern void efx_farch_irq_disable_master(struct efx_nic *efx);
|
||||
extern irqreturn_t efx_farch_msi_interrupt(int irq, void *dev_id);
|
||||
extern irqreturn_t efx_farch_legacy_interrupt(int irq, void *dev_id);
|
||||
extern irqreturn_t efx_farch_fatal_interrupt(struct efx_nic *efx);
|
||||
|
||||
static inline int efx_nic_event_test_irq_cpu(struct efx_channel *channel)
|
||||
{
|
||||
@@ -317,36 +447,40 @@ static inline int efx_nic_irq_test_irq_cpu(struct efx_nic *efx)
|
||||
}
|
||||
|
||||
/* Global Resources */
|
||||
extern int efx_farch_fini_dmaq(struct efx_nic *efx);
|
||||
extern int efx_nic_flush_queues(struct efx_nic *efx);
|
||||
extern void siena_prepare_flush(struct efx_nic *efx);
|
||||
extern int efx_farch_fini_dmaq(struct efx_nic *efx);
|
||||
extern void siena_finish_flush(struct efx_nic *efx);
|
||||
extern void falcon_start_nic_stats(struct efx_nic *efx);
|
||||
extern void falcon_stop_nic_stats(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);
|
||||
extern void efx_farch_dimension_resources(struct efx_nic *efx, unsigned sram_lim_qw);
|
||||
extern void efx_farch_init_common(struct efx_nic *efx);
|
||||
static inline void efx_nic_push_rx_indir_table(struct efx_nic *efx)
|
||||
{
|
||||
efx->type->rx_push_indir_table(efx);
|
||||
}
|
||||
extern void efx_farch_rx_push_indir_table(struct efx_nic *efx);
|
||||
|
||||
int efx_nic_alloc_buffer(struct efx_nic *efx, struct efx_buffer *buffer,
|
||||
unsigned int len, gfp_t gfp_flags);
|
||||
void efx_nic_free_buffer(struct efx_nic *efx, struct efx_buffer *buffer);
|
||||
|
||||
/* Tests */
|
||||
struct efx_nic_register_test {
|
||||
struct efx_farch_register_test {
|
||||
unsigned address;
|
||||
efx_oword_t mask;
|
||||
};
|
||||
extern int efx_nic_test_registers(struct efx_nic *efx,
|
||||
const struct efx_nic_register_test *regs,
|
||||
size_t n_regs);
|
||||
extern int efx_farch_test_registers(struct efx_nic *efx,
|
||||
const struct efx_farch_register_test *regs,
|
||||
size_t n_regs);
|
||||
|
||||
extern size_t efx_nic_get_regs_len(struct efx_nic *efx);
|
||||
extern void efx_nic_get_regs(struct efx_nic *efx, void *buf);
|
||||
|
||||
#define EFX_MAX_FLUSH_TIME 5000
|
||||
|
||||
extern void efx_generate_event(struct efx_nic *efx, unsigned int evq,
|
||||
efx_qword_t *event);
|
||||
extern void efx_farch_generate_event(struct efx_nic *efx, unsigned int evq,
|
||||
efx_qword_t *event);
|
||||
|
||||
#endif /* EFX_NIC_H */
|
||||
|
Reference in New Issue
Block a user