diff options
author | Ben Hutchings <bhutchings@solarflare.com> | 2009-11-29 15:15:41 +0000 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2009-11-29 17:23:57 -0800 |
commit | 8880f4ec21e668dcab3c6d387524a887e5bcbf73 (patch) | |
tree | d2f34eec2fba31f3b3141c2e580846e92c4e554c /drivers/net/sfc/nic.c | |
parent | afd4aea03f597f29421dc5767e7d1f754730ec23 (diff) | |
download | op-kernel-dev-8880f4ec21e668dcab3c6d387524a887e5bcbf73.zip op-kernel-dev-8880f4ec21e668dcab3c6d387524a887e5bcbf73.tar.gz |
sfc: Add support for SFC9000 family (2)
This integrates support for the SFC9000 family of 10G Ethernet
controllers and LAN-on-motherboard chips, starting with the SFL9021
'Siena' and SFC9020 'Bethpage'.
Credit for this code is largely due to my colleagues at Solarflare:
Guido Barzini
Steve Hodgson
Kieran Mansley
Matthew Slattery
Neil Turton
Signed-off-by: Ben Hutchings <bhutchings@solarflare.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/sfc/nic.c')
-rw-r--r-- | drivers/net/sfc/nic.c | 63 |
1 files changed, 49 insertions, 14 deletions
diff --git a/drivers/net/sfc/nic.c b/drivers/net/sfc/nic.c index 55dbd79..5ac4b1a 100644 --- a/drivers/net/sfc/nic.c +++ b/drivers/net/sfc/nic.c @@ -997,6 +997,9 @@ int efx_nic_process_eventq(struct efx_channel *channel, int rx_quota) case FSE_AZ_EV_CODE_DRIVER_EV: efx_handle_driver_event(channel, &event); break; + case FSE_CZ_EV_CODE_MCDI_EV: + efx_mcdi_process_event(channel, &event); + break; default: EFX_ERR(channel->efx, "channel %d unknown event type %d" " (data " EFX_QWORD_FMT ")\n", channel->channel, @@ -1025,13 +1028,21 @@ int efx_nic_probe_eventq(struct efx_channel *channel) void efx_nic_init_eventq(struct efx_channel *channel) { - efx_oword_t evq_ptr; + efx_oword_t reg; struct efx_nic *efx = channel->efx; EFX_LOG(efx, "channel %d event queue in special buffers %d-%d\n", channel->channel, channel->eventq.index, channel->eventq.index + channel->eventq.entries - 1); + if (efx_nic_rev(efx) >= EFX_REV_SIENA_A0) { + 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, ®, FR_BZ_TIMER_TBL, channel->channel); + } + /* Pin event queue buffer */ efx_init_special_buffer(efx, &channel->eventq); @@ -1039,11 +1050,11 @@ void efx_nic_init_eventq(struct efx_channel *channel) memset(channel->eventq.addr, 0xff, channel->eventq.len); /* Push event queue to card */ - EFX_POPULATE_OWORD_3(evq_ptr, + EFX_POPULATE_OWORD_3(reg, FRF_AZ_EVQ_EN, 1, FRF_AZ_EVQ_SIZE, __ffs(channel->eventq.entries), FRF_AZ_EVQ_BUF_BASE_ID, channel->eventq.index); - efx_writeo_table(efx, &evq_ptr, efx->type->evq_ptr_tbl_base, + efx_writeo_table(efx, ®, efx->type->evq_ptr_tbl_base, channel->channel); efx->type->push_irq_moderation(channel); @@ -1051,13 +1062,15 @@ void efx_nic_init_eventq(struct efx_channel *channel) void efx_nic_fini_eventq(struct efx_channel *channel) { - efx_oword_t eventq_ptr; + efx_oword_t reg; struct efx_nic *efx = channel->efx; /* Remove event queue from card */ - EFX_ZERO_OWORD(eventq_ptr); - efx_writeo_table(efx, &eventq_ptr, efx->type->evq_ptr_tbl_base, + EFX_ZERO_OWORD(reg); + efx_writeo_table(efx, ®, efx->type->evq_ptr_tbl_base, channel->channel); + if (efx_nic_rev(efx) >= EFX_REV_SIENA_A0) + efx_writeo_table(efx, ®, FR_BZ_TIMER_TBL, channel->channel); /* Unpin event queue */ efx_fini_special_buffer(efx, &channel->eventq); @@ -1220,8 +1233,15 @@ static inline void efx_nic_interrupts(struct efx_nic *efx, bool enabled, bool force) { efx_oword_t int_en_reg_ker; + unsigned int level = 0; + + if (EFX_WORKAROUND_17213(efx) && !EFX_INT_MODE_USE_MSI(efx)) + /* Set the level always even if we're generating a test + * interrupt, because our legacy interrupt handler is safe */ + level = 0x1f; - EFX_POPULATE_OWORD_2(int_en_reg_ker, + EFX_POPULATE_OWORD_3(int_en_reg_ker, + FRF_AZ_KER_INT_LEVE_SEL, level, FRF_AZ_KER_INT_KER, force, FRF_AZ_DRV_INT_EN_KER, enabled); efx_writeo(efx, &int_en_reg_ker, FR_AZ_INT_EN_KER); @@ -1334,15 +1354,30 @@ static irqreturn_t efx_legacy_interrupt(int irq, void *dev_id) if (unlikely(syserr)) return efx_nic_fatal_interrupt(efx); - /* Schedule processing of any interrupting queues */ - efx_for_each_channel(channel, efx) { - if ((queues & 1) || - efx_event_present( - efx_event(channel, channel->eventq_read_ptr))) { + if (queues != 0) { + if (EFX_WORKAROUND_15783(efx)) + efx->irq_zero_count = 0; + + /* Schedule processing of any interrupting queues */ + efx_for_each_channel(channel, efx) { + if (queues & 1) + efx_schedule_channel(channel); + queues >>= 1; + } + result = IRQ_HANDLED; + + } else if (EFX_WORKAROUND_15783(efx) && + efx->irq_zero_count++ == 0) { + efx_qword_t *event; + + /* Ensure we rearm all event queues */ + efx_for_each_channel(channel, efx) { + event = efx_event(channel, channel->eventq_read_ptr); + if (efx_event_present(event)) efx_schedule_channel(channel); - result = IRQ_HANDLED; } - queues >>= 1; + + result = IRQ_HANDLED; } if (result == IRQ_HANDLED) { |