summaryrefslogtreecommitdiffstats
path: root/drivers/net/sfc/nic.c
diff options
context:
space:
mode:
authorBen Hutchings <bhutchings@solarflare.com>2009-11-29 15:15:41 +0000
committerDavid S. Miller <davem@davemloft.net>2009-11-29 17:23:57 -0800
commit8880f4ec21e668dcab3c6d387524a887e5bcbf73 (patch)
treed2f34eec2fba31f3b3141c2e580846e92c4e554c /drivers/net/sfc/nic.c
parentafd4aea03f597f29421dc5767e7d1f754730ec23 (diff)
downloadop-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.c63
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, &reg, 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, &reg, 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, &reg, efx->type->evq_ptr_tbl_base,
channel->channel);
+ if (efx_nic_rev(efx) >= EFX_REV_SIENA_A0)
+ efx_writeo_table(efx, &reg, 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) {
OpenPOWER on IntegriCloud