sfc: Add efx_nic_type operation for identity LED control
[safe/jmp/linux-2.6] / drivers / net / sfc / falcon.c
index e1b9ce3..61cc994 100644 (file)
@@ -36,8 +36,6 @@
  **************************************************************************
  */
 
-static int disable_dma_stats;
-
 /* This is set to 16 for a good reason.  In summary, if larger than
  * 16, the descriptor cache holds more than a default socket
  * buffer's worth of packets (for UDP we can only have at most one
@@ -47,11 +45,9 @@ static int disable_dma_stats;
  */
 #define TX_DC_ENTRIES 16
 #define TX_DC_ENTRIES_ORDER 1
-#define TX_DC_BASE 0x130000
 
 #define RX_DC_ENTRIES 64
 #define RX_DC_ENTRIES_ORDER 3
-#define RX_DC_BASE 0x100000
 
 static const unsigned int
 /* "Large" EEPROM device: Atmel AT25640 or similar
@@ -113,7 +109,7 @@ MODULE_PARM_DESC(rx_xon_thresh_bytes, "RX fifo XON threshold");
 #define FALCON_RX_FLUSH_COUNT 4
 
 #define FALCON_IS_DUAL_FUNC(efx)               \
-       (falcon_rev(efx) < FALCON_REV_B0)
+       (efx_nic_rev(efx) < EFX_REV_FALCON_B0)
 
 /**************************************************************************
  *
@@ -449,7 +445,7 @@ void falcon_init_tx(struct efx_tx_queue *tx_queue)
                              FRF_AZ_TX_DESCQ_TYPE, 0,
                              FRF_BZ_TX_NON_IP_DROP_DIS, 1);
 
-       if (falcon_rev(efx) >= FALCON_REV_B0) {
+       if (efx_nic_rev(efx) >= EFX_REV_FALCON_B0) {
                int csum = tx_queue->queue == EFX_TX_QUEUE_OFFLOAD_CSUM;
                EFX_SET_OWORD_FIELD(tx_desc_ptr, FRF_BZ_TX_IP_CHKSM_DIS, !csum);
                EFX_SET_OWORD_FIELD(tx_desc_ptr, FRF_BZ_TX_TCP_CHKSM_DIS,
@@ -459,7 +455,7 @@ void falcon_init_tx(struct efx_tx_queue *tx_queue)
        efx_writeo_table(efx, &tx_desc_ptr, efx->type->txd_ptr_tbl_base,
                         tx_queue->queue);
 
-       if (falcon_rev(efx) < FALCON_REV_B0) {
+       if (efx_nic_rev(efx) < EFX_REV_FALCON_B0) {
                efx_oword_t reg;
 
                /* Only 128 bits in this register */
@@ -576,7 +572,7 @@ void falcon_init_rx(struct efx_rx_queue *rx_queue)
 {
        efx_oword_t rx_desc_ptr;
        struct efx_nic *efx = rx_queue->efx;
-       bool is_b0 = falcon_rev(efx) >= FALCON_REV_B0;
+       bool is_b0 = efx_nic_rev(efx) >= EFX_REV_FALCON_B0;
        bool iscsi_digest_en = is_b0;
 
        EFX_LOG(efx, "RX queue %d ring in special buffers %d-%d\n",
@@ -738,7 +734,7 @@ static void falcon_handle_rx_not_ok(struct efx_rx_queue *rx_queue,
        bool rx_ev_tcp_udp_chksum_err, rx_ev_eth_crc_err;
        bool rx_ev_frm_trunc, rx_ev_drib_nib, rx_ev_tobe_disc;
        bool rx_ev_other_err, rx_ev_pause_frm;
-       bool rx_ev_ip_frag_err, rx_ev_hdr_type, rx_ev_mcast_pkt;
+       bool rx_ev_hdr_type, rx_ev_mcast_pkt;
        unsigned rx_ev_pkt_type;
 
        rx_ev_hdr_type = EFX_QWORD_FIELD(*event, FSF_AZ_RX_EV_HDR_TYPE);
@@ -747,14 +743,13 @@ static void falcon_handle_rx_not_ok(struct efx_rx_queue *rx_queue,
        rx_ev_pkt_type = EFX_QWORD_FIELD(*event, FSF_AZ_RX_EV_PKT_TYPE);
        rx_ev_buf_owner_id_err = EFX_QWORD_FIELD(*event,
                                                 FSF_AZ_RX_EV_BUF_OWNER_ID_ERR);
-       rx_ev_ip_frag_err = EFX_QWORD_FIELD(*event, FSF_AZ_RX_EV_IP_FRAG_ERR);
        rx_ev_ip_hdr_chksum_err = EFX_QWORD_FIELD(*event,
                                                  FSF_AZ_RX_EV_IP_HDR_CHKSUM_ERR);
        rx_ev_tcp_udp_chksum_err = EFX_QWORD_FIELD(*event,
                                                   FSF_AZ_RX_EV_TCP_UDP_CHKSUM_ERR);
        rx_ev_eth_crc_err = EFX_QWORD_FIELD(*event, FSF_AZ_RX_EV_ETH_CRC_ERR);
        rx_ev_frm_trunc = EFX_QWORD_FIELD(*event, FSF_AZ_RX_EV_FRM_TRUNC);
-       rx_ev_drib_nib = ((falcon_rev(efx) >= FALCON_REV_B0) ?
+       rx_ev_drib_nib = ((efx_nic_rev(efx) >= EFX_REV_FALCON_B0) ?
                          0 : EFX_QWORD_FIELD(*event, FSF_AA_RX_EV_DRIB_NIB));
        rx_ev_pause_frm = EFX_QWORD_FIELD(*event, FSF_AZ_RX_EV_PAUSE_FRM_ERR);
 
@@ -775,8 +770,6 @@ static void falcon_handle_rx_not_ok(struct efx_rx_queue *rx_queue,
                else if (rx_ev_tcp_udp_chksum_err)
                        ++rx_queue->channel->n_rx_tcp_udp_chksum_err;
        }
-       if (rx_ev_ip_frag_err)
-               ++rx_queue->channel->n_rx_ip_frag_err;
 
        /* The frame must be discarded if any of these are true. */
        *discard = (rx_ev_eth_crc_err | rx_ev_frm_trunc | rx_ev_drib_nib |
@@ -859,7 +852,7 @@ static void falcon_handle_rx_event(struct efx_channel *channel,
                 * UDP/IPv4, then we can rely on the hardware checksum.
                 */
                checksummed =
-                       efx->rx_checksum_enabled &&
+                       likely(efx->rx_checksum_enabled) &&
                        (rx_ev_hdr_type == FSE_AB_RX_EV_HDR_TYPE_IPV4_TCP ||
                         rx_ev_hdr_type == FSE_AB_RX_EV_HDR_TYPE_IPV4_UDP);
        } else {
@@ -874,8 +867,10 @@ static void falcon_handle_rx_event(struct efx_channel *channel,
                unsigned int rx_ev_mcast_hash_match =
                        EFX_QWORD_FIELD(*event, FSF_AZ_RX_EV_MCAST_HASH_MATCH);
 
-               if (unlikely(!rx_ev_mcast_hash_match))
+               if (unlikely(!rx_ev_mcast_hash_match)) {
+                       ++channel->n_rx_mcast_mismatch;
                        discard = true;
+               }
        }
 
        channel->irq_mod_score += 2;
@@ -895,18 +890,17 @@ static void falcon_handle_global_event(struct efx_channel *channel,
        if (EFX_QWORD_FIELD(*event, FSF_AB_GLB_EV_G_PHY0_INTR) ||
            EFX_QWORD_FIELD(*event, FSF_AB_GLB_EV_XG_PHY0_INTR) ||
            EFX_QWORD_FIELD(*event, FSF_AB_GLB_EV_XFP_PHY0_INTR)) {
-               efx->phy_op->clear_interrupt(efx);
-               queue_work(efx->workqueue, &efx->phy_work);
+               /* Ignored */
                handled = true;
        }
 
-       if ((falcon_rev(efx) >= FALCON_REV_B0) &&
+       if ((efx_nic_rev(efx) >= EFX_REV_FALCON_B0) &&
            EFX_QWORD_FIELD(*event, FSF_BB_GLB_EV_XG_MGT_INTR)) {
-               queue_work(efx->workqueue, &efx->mac_work);
+               efx->xmac_poll_required = true;
                handled = true;
        }
 
-       if (falcon_rev(efx) <= FALCON_REV_A1 ?
+       if (efx_nic_rev(efx) <= EFX_REV_FALCON_A1 ?
            EFX_QWORD_FIELD(*event, FSF_AA_GLB_EV_RX_RECOVERY) :
            EFX_QWORD_FIELD(*event, FSF_BB_GLB_EV_RX_RECOVERY)) {
                EFX_ERR(efx, "channel %d seen global RX_RESET "
@@ -1047,7 +1041,7 @@ int falcon_process_eventq(struct efx_channel *channel, int rx_quota)
        return rx_packets;
 }
 
-void falcon_set_int_moderation(struct efx_channel *channel)
+static void falcon_push_irq_moderation(struct efx_channel *channel)
 {
        efx_dword_t timer_cmd;
        struct efx_nic *efx = channel->efx;
@@ -1104,7 +1098,7 @@ void falcon_init_eventq(struct efx_channel *channel)
        efx_writeo_table(efx, &evq_ptr, efx->type->evq_ptr_tbl_base,
                         channel->channel);
 
-       falcon_set_int_moderation(channel);
+       falcon_push_irq_moderation(channel);
 }
 
 void falcon_fini_eventq(struct efx_channel *channel)
@@ -1142,20 +1136,6 @@ void falcon_generate_test_event(struct efx_channel *channel, unsigned int magic)
        falcon_generate_event(channel, &test_event);
 }
 
-void falcon_sim_phy_event(struct efx_nic *efx)
-{
-       efx_qword_t phy_event;
-
-       EFX_POPULATE_QWORD_1(phy_event, FSF_AZ_EV_CODE,
-                            FSE_AZ_EV_CODE_GLOBAL_EV);
-       if (EFX_IS10G(efx))
-               EFX_SET_QWORD_FIELD(phy_event, FSF_AB_GLB_EV_XG_PHY0_INTR, 1);
-       else
-               EFX_SET_QWORD_FIELD(phy_event, FSF_AB_GLB_EV_G_PHY0_INTR, 1);
-
-       falcon_generate_event(&efx->channel[0], &phy_event);
-}
-
 /**************************************************************************
  *
  * Flush handling
@@ -1213,6 +1193,8 @@ static void falcon_poll_flush_events(struct efx_nic *efx)
        channel->eventq_read_ptr = read_ptr;
 }
 
+static void falcon_deconfigure_mac_wrapper(struct efx_nic *efx);
+
 static void falcon_prepare_flush(struct efx_nic *efx)
 {
        falcon_deconfigure_mac_wrapper(efx);
@@ -1232,7 +1214,8 @@ int falcon_flush_queues(struct efx_nic *efx)
        struct efx_tx_queue *tx_queue;
        int i, tx_pending, rx_pending;
 
-       falcon_prepare_flush(efx);
+       /* If necessary prepare the hardware for flushing */
+       efx->type->prepare_flush(efx);
 
        /* Flush all tx queues in parallel */
        efx_for_each_tx_queue(tx_queue, efx)
@@ -1310,19 +1293,11 @@ static inline void falcon_interrupts(struct efx_nic *efx, int enabled,
 
 void falcon_enable_interrupts(struct efx_nic *efx)
 {
-       efx_oword_t int_adr_reg_ker;
        struct efx_channel *channel;
 
        EFX_ZERO_OWORD(*((efx_oword_t *) efx->irq_status.addr));
        wmb(); /* Ensure interrupt vector is clear before interrupts enabled */
 
-       /* Program address */
-       EFX_POPULATE_OWORD_2(int_adr_reg_ker,
-                            FRF_AZ_NORM_INT_VEC_DIS_KER,
-                            EFX_INT_MODE_USE_MSI(efx),
-                            FRF_AZ_INT_ADR_KER, efx->irq_status.dma_addr);
-       efx_writeo(efx, &int_adr_reg_ker, FR_AZ_INT_ADR_KER);
-
        /* Enable interrupts */
        falcon_interrupts(efx, 1, 0);
 
@@ -1491,8 +1466,8 @@ static irqreturn_t falcon_legacy_interrupt_a1(int irq, void *dev_id)
        /* Determine interrupting queues, clear interrupt status
         * register and acknowledge the device interrupt.
         */
-       BUILD_BUG_ON(INT_EVQS_WIDTH > EFX_MAX_CHANNELS);
-       queues = EFX_OWORD_FIELD(*int_ker, INT_EVQS);
+       BUILD_BUG_ON(FSF_AZ_NET_IVEC_INT_Q_WIDTH > EFX_MAX_CHANNELS);
+       queues = EFX_OWORD_FIELD(*int_ker, FSF_AZ_NET_IVEC_INT_Q);
        EFX_ZERO_OWORD(*int_ker);
        wmb(); /* Ensure the vector is cleared before interrupt ack */
        falcon_irq_ack_a1(efx);
@@ -1528,7 +1503,7 @@ static irqreturn_t falcon_msi_interrupt(int irq, void *dev_id)
                  irq, raw_smp_processor_id(), EFX_OWORD_VAL(*int_ker));
 
        /* Check to see if we have a serious error condition */
-       syserr = EFX_OWORD_FIELD(*int_ker, FATAL_INT);
+       syserr = EFX_OWORD_FIELD(*int_ker, FSF_AZ_NET_IVEC_FATAL_INT);
        if (unlikely(syserr))
                return falcon_fatal_interrupt(efx);
 
@@ -1548,7 +1523,7 @@ static void falcon_setup_rss_indir_table(struct efx_nic *efx)
        unsigned long offset;
        efx_dword_t dword;
 
-       if (falcon_rev(efx) < FALCON_REV_B0)
+       if (efx_nic_rev(efx) < EFX_REV_FALCON_B0)
                return;
 
        for (offset = FR_BZ_RX_INDIRECTION_TBL;
@@ -1571,7 +1546,7 @@ int falcon_init_interrupt(struct efx_nic *efx)
 
        if (!EFX_INT_MODE_USE_MSI(efx)) {
                irq_handler_t handler;
-               if (falcon_rev(efx) >= FALCON_REV_B0)
+               if (efx_nic_rev(efx) >= EFX_REV_FALCON_B0)
                        handler = falcon_legacy_interrupt_b0;
                else
                        handler = falcon_legacy_interrupt_a1;
@@ -1618,7 +1593,7 @@ void falcon_fini_interrupt(struct efx_nic *efx)
        }
 
        /* ACK legacy interrupt */
-       if (falcon_rev(efx) >= FALCON_REV_B0)
+       if (efx_nic_rev(efx) >= EFX_REV_FALCON_B0)
                efx_reado(efx, &reg, FR_BZ_INT_ISR0);
        else
                falcon_irq_ack_a1(efx);
@@ -1853,12 +1828,23 @@ int falcon_spi_write(const struct efx_spi_device *spi, loff_t start,
  **************************************************************************
  */
 
-static int falcon_reset_macs(struct efx_nic *efx)
+static void falcon_push_multicast_hash(struct efx_nic *efx)
 {
-       efx_oword_t reg;
+       union efx_multicast_hash *mc_hash = &efx->multicast_hash;
+
+       WARN_ON(!mutex_is_locked(&efx->mac_lock));
+
+       efx_writeo(efx, &mc_hash->oword[0], FR_AB_MAC_MC_HASH_REG0);
+       efx_writeo(efx, &mc_hash->oword[1], FR_AB_MAC_MC_HASH_REG1);
+}
+
+static void falcon_reset_macs(struct efx_nic *efx)
+{
+       struct falcon_nic_data *nic_data = efx->nic_data;
+       efx_oword_t reg, mac_ctrl;
        int count;
 
-       if (falcon_rev(efx) < FALCON_REV_B0) {
+       if (efx_nic_rev(efx) < EFX_REV_FALCON_B0) {
                /* It's not safe to use GLB_CTL_REG to reset the
                 * macs, so instead use the internal MAC resets
                 */
@@ -1870,7 +1856,7 @@ static int falcon_reset_macs(struct efx_nic *efx)
                        EFX_POPULATE_OWORD_1(reg, FRF_AB_GM_SW_RST, 0);
                        efx_writeo(efx, &reg, FR_AB_GM_CFG1);
                        udelay(1000);
-                       return 0;
+                       return;
                } else {
                        EFX_POPULATE_OWORD_1(reg, FRF_AB_XM_CORE_RST, 1);
                        efx_writeo(efx, &reg, FR_AB_XM_GLB_CFG);
@@ -1879,22 +1865,20 @@ static int falcon_reset_macs(struct efx_nic *efx)
                                efx_reado(efx, &reg, FR_AB_XM_GLB_CFG);
                                if (EFX_OWORD_FIELD(reg, FRF_AB_XM_CORE_RST) ==
                                    0)
-                                       return 0;
+                                       return;
                                udelay(10);
                        }
 
                        EFX_ERR(efx, "timed out waiting for XMAC core reset\n");
-                       return -ETIMEDOUT;
                }
        }
 
-       /* MAC stats will fail whilst the TX fifo is draining. Serialise
-        * the drain sequence with the statistics fetch */
-       efx_stats_disable(efx);
+       /* Mac stats will fail whist the TX fifo is draining */
+       WARN_ON(nic_data->stats_disable_count == 0);
 
-       efx_reado(efx, &reg, FR_AB_MAC_CTRL);
-       EFX_SET_OWORD_FIELD(reg, FRF_BB_TXFIFO_DRAIN_EN, 1);
-       efx_writeo(efx, &reg, FR_AB_MAC_CTRL);
+       efx_reado(efx, &mac_ctrl, FR_AB_MAC_CTRL);
+       EFX_SET_OWORD_FIELD(mac_ctrl, FRF_BB_TXFIFO_DRAIN_EN, 1);
+       efx_writeo(efx, &mac_ctrl, FR_AB_MAC_CTRL);
 
        efx_reado(efx, &reg, FR_AB_GLB_CTL);
        EFX_SET_OWORD_FIELD(reg, FRF_AB_RST_XGTX, 1);
@@ -1920,21 +1904,16 @@ static int falcon_reset_macs(struct efx_nic *efx)
                udelay(10);
        }
 
-       efx_stats_enable(efx);
-
-       /* If we've reset the EM block and the link is up, then
-        * we'll have to kick the XAUI link so the PHY can recover */
-       if (efx->link_state.up && EFX_IS10G(efx) && EFX_WORKAROUND_5147(efx))
-               falcon_reset_xaui(efx);
-
-       return 0;
+       /* Ensure the correct MAC is selected before statistics
+        * are re-enabled by the caller */
+       efx_writeo(efx, &mac_ctrl, FR_AB_MAC_CTRL);
 }
 
 void falcon_drain_tx_fifo(struct efx_nic *efx)
 {
        efx_oword_t reg;
 
-       if ((falcon_rev(efx) < FALCON_REV_B0) ||
+       if ((efx_nic_rev(efx) < EFX_REV_FALCON_B0) ||
            (efx->loopback_mode != LOOPBACK_NONE))
                return;
 
@@ -1946,11 +1925,11 @@ void falcon_drain_tx_fifo(struct efx_nic *efx)
        falcon_reset_macs(efx);
 }
 
-void falcon_deconfigure_mac_wrapper(struct efx_nic *efx)
+static void falcon_deconfigure_mac_wrapper(struct efx_nic *efx)
 {
        efx_oword_t reg;
 
-       if (falcon_rev(efx) < FALCON_REV_B0)
+       if (efx_nic_rev(efx) < EFX_REV_FALCON_B0)
                return;
 
        /* Isolate the MAC -> RX */
@@ -1958,8 +1937,8 @@ void falcon_deconfigure_mac_wrapper(struct efx_nic *efx)
        EFX_SET_OWORD_FIELD(reg, FRF_BZ_RX_INGR_EN, 0);
        efx_writeo(efx, &reg, FR_AZ_RX_CFG);
 
-       if (!efx->link_state.up)
-               falcon_drain_tx_fifo(efx);
+       /* Isolate TX -> MAC */
+       falcon_drain_tx_fifo(efx);
 }
 
 void falcon_reconfigure_mac_wrapper(struct efx_nic *efx)
@@ -1967,7 +1946,6 @@ void falcon_reconfigure_mac_wrapper(struct efx_nic *efx)
        struct efx_link_state *link_state = &efx->link_state;
        efx_oword_t reg;
        int link_speed;
-       bool tx_fc;
 
        switch (link_state->speed) {
        case 10000: link_speed = 3; break;
@@ -1987,7 +1965,7 @@ void falcon_reconfigure_mac_wrapper(struct efx_nic *efx)
                             FRF_AB_MAC_SPEED, link_speed);
        /* On B0, MAC backpressure can be disabled and packets get
         * discarded. */
-       if (falcon_rev(efx) >= FALCON_REV_B0) {
+       if (efx_nic_rev(efx) >= EFX_REV_FALCON_B0) {
                EFX_SET_OWORD_FIELD(reg, FRF_BB_TXFIFO_DRAIN_EN,
                                    !link_state->up);
        }
@@ -1995,40 +1973,31 @@ void falcon_reconfigure_mac_wrapper(struct efx_nic *efx)
        efx_writeo(efx, &reg, FR_AB_MAC_CTRL);
 
        /* Restore the multicast hash registers. */
-       falcon_set_multicast_hash(efx);
+       falcon_push_multicast_hash(efx);
 
-       /* Transmission of pause frames when RX crosses the threshold is
-        * covered by RX_XOFF_MAC_EN and XM_TX_CFG_REG:XM_FCNTL.
-        * Action on receipt of pause frames is controller by XM_DIS_FCNTL */
-       tx_fc = !!(efx->link_state.fc & EFX_FC_TX);
        efx_reado(efx, &reg, FR_AZ_RX_CFG);
-       EFX_SET_OWORD_FIELD(reg, FRF_AZ_RX_XOFF_MAC_EN, tx_fc);
-
+       /* Enable XOFF signal from RX FIFO (we enabled it during NIC
+        * initialisation but it may read back as 0) */
+       EFX_SET_OWORD_FIELD(reg, FRF_AZ_RX_XOFF_MAC_EN, 1);
        /* Unisolate the MAC -> RX */
-       if (falcon_rev(efx) >= FALCON_REV_B0)
+       if (efx_nic_rev(efx) >= EFX_REV_FALCON_B0)
                EFX_SET_OWORD_FIELD(reg, FRF_BZ_RX_INGR_EN, 1);
        efx_writeo(efx, &reg, FR_AZ_RX_CFG);
 }
 
-int falcon_dma_stats(struct efx_nic *efx, unsigned int done_offset)
+static void falcon_stats_request(struct efx_nic *efx)
 {
+       struct falcon_nic_data *nic_data = efx->nic_data;
        efx_oword_t reg;
-       u32 *dma_done;
-       int i;
 
-       if (disable_dma_stats)
-               return 0;
+       WARN_ON(nic_data->stats_pending);
+       WARN_ON(nic_data->stats_disable_count);
 
-       /* Statistics fetch will fail if the MAC is in TX drain */
-       if (falcon_rev(efx) >= FALCON_REV_B0) {
-               efx_oword_t temp;
-               efx_reado(efx, &temp, FR_AB_MAC_CTRL);
-               if (EFX_OWORD_FIELD(temp, FRF_BB_TXFIFO_DRAIN_EN))
-                       return 0;
-       }
+       if (nic_data->stats_dma_done == NULL)
+               return; /* no mac selected */
 
-       dma_done = (efx->stats_buffer.addr + done_offset);
-       *dma_done = FALCON_STATS_NOT_DONE;
+       *nic_data->stats_dma_done = FALCON_STATS_NOT_DONE;
+       nic_data->stats_pending = true;
        wmb(); /* ensure done flag is clear */
 
        /* Initiate DMA transfer of stats */
@@ -2038,17 +2007,90 @@ int falcon_dma_stats(struct efx_nic *efx, unsigned int done_offset)
                             efx->stats_buffer.dma_addr);
        efx_writeo(efx, &reg, FR_AB_MAC_STAT_DMA);
 
-       /* Wait for transfer to complete */
-       for (i = 0; i < 400; i++) {
-               if (*(volatile u32 *)dma_done == FALCON_STATS_DONE) {
-                       rmb(); /* Ensure the stats are valid. */
-                       return 0;
-               }
-               udelay(10);
+       mod_timer(&nic_data->stats_timer, round_jiffies_up(jiffies + HZ / 2));
+}
+
+static void falcon_stats_complete(struct efx_nic *efx)
+{
+       struct falcon_nic_data *nic_data = efx->nic_data;
+
+       if (!nic_data->stats_pending)
+               return;
+
+       nic_data->stats_pending = 0;
+       if (*nic_data->stats_dma_done == FALCON_STATS_DONE) {
+               rmb(); /* read the done flag before the stats */
+               efx->mac_op->update_stats(efx);
+       } else {
+               EFX_ERR(efx, "timed out waiting for statistics\n");
        }
+}
 
-       EFX_ERR(efx, "timed out waiting for statistics\n");
-       return -ETIMEDOUT;
+static void falcon_stats_timer_func(unsigned long context)
+{
+       struct efx_nic *efx = (struct efx_nic *)context;
+       struct falcon_nic_data *nic_data = efx->nic_data;
+
+       spin_lock(&efx->stats_lock);
+
+       falcon_stats_complete(efx);
+       if (nic_data->stats_disable_count == 0)
+               falcon_stats_request(efx);
+
+       spin_unlock(&efx->stats_lock);
+}
+
+static void falcon_switch_mac(struct efx_nic *efx);
+
+static bool falcon_loopback_link_poll(struct efx_nic *efx)
+{
+       struct efx_link_state old_state = efx->link_state;
+
+       WARN_ON(!mutex_is_locked(&efx->mac_lock));
+       WARN_ON(!LOOPBACK_INTERNAL(efx));
+
+       efx->link_state.fd = true;
+       efx->link_state.fc = efx->wanted_fc;
+       efx->link_state.up = true;
+
+       if (efx->loopback_mode == LOOPBACK_GMAC)
+               efx->link_state.speed = 1000;
+       else
+               efx->link_state.speed = 10000;
+
+       return !efx_link_state_equal(&efx->link_state, &old_state);
+}
+
+static int falcon_reconfigure_port(struct efx_nic *efx)
+{
+       int rc;
+
+       WARN_ON(efx_nic_rev(efx) > EFX_REV_FALCON_B0);
+
+       /* Poll the PHY link state *before* reconfiguring it. This means we
+        * will pick up the correct speed (in loopback) to select the correct
+        * MAC.
+        */
+       if (LOOPBACK_INTERNAL(efx))
+               falcon_loopback_link_poll(efx);
+       else
+               efx->phy_op->poll(efx);
+
+       falcon_stop_nic_stats(efx);
+       falcon_deconfigure_mac_wrapper(efx);
+
+       falcon_switch_mac(efx);
+
+       efx->phy_op->reconfigure(efx);
+       rc = efx->mac_op->reconfigure(efx);
+       BUG_ON(rc);
+
+       falcon_start_nic_stats(efx);
+
+       /* Synchronise efx->link_state with the kernel */
+       efx_link_status_changed(efx);
+
+       return 0;
 }
 
 /**************************************************************************
@@ -2094,7 +2136,7 @@ static int falcon_mdio_write(struct net_device *net_dev,
        EFX_REGDUMP(efx, "writing MDIO %d register %d.%d with 0x%04x\n",
                    prtad, devad, addr, value);
 
-       spin_lock_bh(&efx->phy_lock);
+       mutex_lock(&efx->mdio_lock);
 
        /* Check MDIO not currently being accessed */
        rc = falcon_gmii_wait(efx);
@@ -2129,8 +2171,8 @@ static int falcon_mdio_write(struct net_device *net_dev,
                udelay(10);
        }
 
- out:
-       spin_unlock_bh(&efx->phy_lock);
+out:
+       mutex_unlock(&efx->mdio_lock);
        return rc;
 }
 
@@ -2142,7 +2184,7 @@ static int falcon_mdio_read(struct net_device *net_dev,
        efx_oword_t reg;
        int rc;
 
-       spin_lock_bh(&efx->phy_lock);
+       mutex_lock(&efx->mdio_lock);
 
        /* Check MDIO not currently being accessed */
        rc = falcon_gmii_wait(efx);
@@ -2178,39 +2220,20 @@ static int falcon_mdio_read(struct net_device *net_dev,
                        prtad, devad, addr, rc);
        }
 
- out:
-       spin_unlock_bh(&efx->phy_lock);
+out:
+       mutex_unlock(&efx->mdio_lock);
        return rc;
 }
 
-int falcon_switch_mac(struct efx_nic *efx)
+static void falcon_clock_mac(struct efx_nic *efx)
 {
-       struct efx_mac_operations *old_mac_op = efx->mac_op;
-       efx_oword_t nic_stat;
        unsigned strap_val;
-       int rc = 0;
-
-       /* Don't try to fetch MAC stats while we're switching MACs */
-       efx_stats_disable(efx);
-
-       /* Internal loopbacks override the phy speed setting */
-       if (efx->loopback_mode == LOOPBACK_GMAC) {
-               efx->link_state.speed = 1000;
-               efx->link_state.fd = true;
-       } else if (LOOPBACK_INTERNAL(efx)) {
-               efx->link_state.speed = 10000;
-               efx->link_state.fd = true;
-       }
-
-       WARN_ON(!mutex_is_locked(&efx->mac_lock));
-       efx->mac_op = (EFX_IS10G(efx) ?
-                      &falcon_xmac_operations : &falcon_gmac_operations);
+       efx_oword_t nic_stat;
 
-       /* Always push the NIC_STAT_REG setting even if the mac hasn't
-        * changed, because this function is run post online reset */
+       /* Configure the NIC generated MAC clock correctly */
        efx_reado(efx, &nic_stat, FR_AB_NIC_STAT);
        strap_val = EFX_IS10G(efx) ? 5 : 3;
-       if (falcon_rev(efx) >= FALCON_REV_B0) {
+       if (efx_nic_rev(efx) >= EFX_REV_FALCON_B0) {
                EFX_SET_OWORD_FIELD(nic_stat, FRF_BB_EE_STRAP_EN, 1);
                EFX_SET_OWORD_FIELD(nic_stat, FRF_BB_EE_STRAP, strap_val);
                efx_writeo(efx, &nic_stat, FR_AB_NIC_STAT);
@@ -2220,22 +2243,39 @@ int falcon_switch_mac(struct efx_nic *efx)
                BUG_ON(EFX_OWORD_FIELD(nic_stat, FRF_AB_STRAP_PINS) !=
                       strap_val);
        }
+}
+
+static void falcon_switch_mac(struct efx_nic *efx)
+{
+       struct efx_mac_operations *old_mac_op = efx->mac_op;
+       struct falcon_nic_data *nic_data = efx->nic_data;
+       unsigned int stats_done_offset;
+
+       WARN_ON(!mutex_is_locked(&efx->mac_lock));
+       WARN_ON(nic_data->stats_disable_count == 0);
+
+       efx->mac_op = (EFX_IS10G(efx) ?
+                      &falcon_xmac_operations : &falcon_gmac_operations);
+
+       if (EFX_IS10G(efx))
+               stats_done_offset = XgDmaDone_offset;
+       else
+               stats_done_offset = GDmaDone_offset;
+       nic_data->stats_dma_done = efx->stats_buffer.addr + stats_done_offset;
 
        if (old_mac_op == efx->mac_op)
-               goto out;
+               return;
+
+       falcon_clock_mac(efx);
 
        EFX_LOG(efx, "selected %cMAC\n", EFX_IS10G(efx) ? 'X' : 'G');
        /* Not all macs support a mac-level link state */
-       efx->mac_up = true;
-
-       rc = falcon_reset_macs(efx);
-out:
-       efx_stats_enable(efx);
-       return rc;
+       efx->xmac_poll_required = false;
+       falcon_reset_macs(efx);
 }
 
 /* This call is responsible for hooking in the MAC and PHY operations */
-int falcon_probe_port(struct efx_nic *efx)
+static int falcon_probe_port(struct efx_nic *efx)
 {
        int rc;
 
@@ -2271,8 +2311,12 @@ int falcon_probe_port(struct efx_nic *efx)
        efx->mdio.mdio_read = falcon_mdio_read;
        efx->mdio.mdio_write = falcon_mdio_write;
 
+       /* Initial assumption */
+       efx->link_state.speed = 10000;
+       efx->link_state.fd = true;
+
        /* Hardware flow ctrl. FalconA RX FIFO too small for pause generation */
-       if (falcon_rev(efx) >= FALCON_REV_B0)
+       if (efx_nic_rev(efx) >= EFX_REV_FALCON_B0)
                efx->wanted_fc = EFX_FC_RX | EFX_FC_TX;
        else
                efx->wanted_fc = EFX_FC_RX;
@@ -2290,40 +2334,19 @@ int falcon_probe_port(struct efx_nic *efx)
        return 0;
 }
 
-void falcon_remove_port(struct efx_nic *efx)
+static void falcon_remove_port(struct efx_nic *efx)
 {
        falcon_free_buffer(efx, &efx->stats_buffer);
 }
 
 /**************************************************************************
  *
- * Multicast filtering
- *
- **************************************************************************
- */
-
-void falcon_set_multicast_hash(struct efx_nic *efx)
-{
-       union efx_multicast_hash *mc_hash = &efx->multicast_hash;
-
-       /* Broadcast packets go through the multicast hash filter.
-        * ether_crc_le() of the broadcast address is 0xbe2612ff
-        * so we always add bit 0xff to the mask.
-        */
-       set_bit_le(0xff, mc_hash->byte);
-
-       efx_writeo(efx, &mc_hash->oword[0], FR_AB_MAC_MC_HASH_REG0);
-       efx_writeo(efx, &mc_hash->oword[1], FR_AB_MAC_MC_HASH_REG1);
-}
-
-
-/**************************************************************************
- *
  * Falcon test code
  *
  **************************************************************************/
 
-int falcon_read_nvram(struct efx_nic *efx, struct falcon_nvconfig *nvconfig_out)
+static int
+falcon_read_nvram(struct efx_nic *efx, struct falcon_nvconfig *nvconfig_out)
 {
        struct falcon_nvconfig *nvconfig;
        struct efx_spi_device *spi;
@@ -2386,6 +2409,11 @@ int falcon_read_nvram(struct efx_nic *efx, struct falcon_nvconfig *nvconfig_out)
        return rc;
 }
 
+static int falcon_test_nvram(struct efx_nic *efx)
+{
+       return falcon_read_nvram(efx, NULL);
+}
+
 /* Registers tested in the falcon register test */
 static struct {
        unsigned address;
@@ -2436,7 +2464,7 @@ static bool efx_masked_compare_oword(const efx_oword_t *a, const efx_oword_t *b,
                ((a->u64[1] ^ b->u64[1]) & mask->u64[1]);
 }
 
-int falcon_test_registers(struct efx_nic *efx)
+static int falcon_b0_test_registers(struct efx_nic *efx)
 {
        unsigned address = 0, i, j;
        efx_oword_t mask, imask, original, reg, buf;
@@ -2498,7 +2526,7 @@ fail:
 
 /* Resets NIC to known state.  This routine must be called in process
  * context and is allowed to sleep. */
-int falcon_reset_hw(struct efx_nic *efx, enum reset_type method)
+static int falcon_reset_hw(struct efx_nic *efx, enum reset_type method)
 {
        struct falcon_nic_data *nic_data = efx->nic_data;
        efx_oword_t glb_ctl_reg_ker;
@@ -2587,6 +2615,44 @@ fail5:
        return rc;
 }
 
+static void falcon_monitor(struct efx_nic *efx)
+{
+       bool link_changed;
+       int rc;
+
+       BUG_ON(!mutex_is_locked(&efx->mac_lock));
+
+       rc = falcon_board(efx)->type->monitor(efx);
+       if (rc) {
+               EFX_ERR(efx, "Board sensor %s; shutting down PHY\n",
+                       (rc == -ERANGE) ? "reported fault" : "failed");
+               efx->phy_mode |= PHY_MODE_LOW_POWER;
+               rc = __efx_reconfigure_port(efx);
+               WARN_ON(rc);
+       }
+
+       if (LOOPBACK_INTERNAL(efx))
+               link_changed = falcon_loopback_link_poll(efx);
+       else
+               link_changed = efx->phy_op->poll(efx);
+
+       if (link_changed) {
+               falcon_stop_nic_stats(efx);
+               falcon_deconfigure_mac_wrapper(efx);
+
+               falcon_switch_mac(efx);
+               rc = efx->mac_op->reconfigure(efx);
+               BUG_ON(rc);
+
+               falcon_start_nic_stats(efx);
+
+               efx_link_status_changed(efx);
+       }
+
+       if (EFX_IS10G(efx))
+               falcon_poll_xmac(efx);
+}
+
 /* Zeroes out the SRAM contents.  This routine must be called in
  * process context and is allowed to sleep.
  */
@@ -2750,30 +2816,23 @@ static int falcon_probe_nic_variant(struct efx_nic *efx)
 
        efx_reado(efx, &nic_stat, FR_AB_NIC_STAT);
 
-       switch (falcon_rev(efx)) {
-       case FALCON_REV_A0:
-       case 0xff:
-               EFX_ERR(efx, "Falcon rev A0 not supported\n");
-               return -ENODEV;
+       if (efx_nic_rev(efx) <= EFX_REV_FALCON_A1) {
+               u8 pci_rev = efx->pci_dev->revision;
 
-       case FALCON_REV_A1:
+               if ((pci_rev == 0xff) || (pci_rev == 0)) {
+                       EFX_ERR(efx, "Falcon rev A0 not supported\n");
+                       return -ENODEV;
+               }
+               if (EFX_OWORD_FIELD(nic_stat, FRF_AB_STRAP_10G) == 0) {
+                       EFX_ERR(efx, "Falcon rev A1 1G not supported\n");
+                       return -ENODEV;
+               }
                if (EFX_OWORD_FIELD(nic_stat, FRF_AA_STRAP_PCIE) == 0) {
                        EFX_ERR(efx, "Falcon rev A1 PCI-X not supported\n");
                        return -ENODEV;
                }
-               break;
-
-       case FALCON_REV_B0:
-               break;
-
-       default:
-               EFX_ERR(efx, "Unknown Falcon rev %d\n", falcon_rev(efx));
-               return -ENODEV;
        }
 
-       /* Initial assumed speed */
-       efx->link_state.speed = EFX_OWORD_FIELD(nic_stat, FRF_AB_STRAP_10G) ? 10000 : 1000;
-
        return 0;
 }
 
@@ -2816,7 +2875,7 @@ static void falcon_probe_spi_devices(struct efx_nic *efx)
                                       large_eeprom_type);
 }
 
-int falcon_probe_nic(struct efx_nic *efx)
+static int falcon_probe_nic(struct efx_nic *efx)
 {
        struct falcon_nic_data *nic_data;
        struct falcon_board *board;
@@ -2895,6 +2954,10 @@ int falcon_probe_nic(struct efx_nic *efx)
                goto fail6;
        }
 
+       nic_data->stats_disable_count = 1;
+       setup_timer(&nic_data->stats_timer, &falcon_stats_timer_func,
+                   (unsigned long)efx);
+
        return 0;
 
  fail6:
@@ -2930,7 +2993,7 @@ static void falcon_init_rx_cfg(struct efx_nic *efx)
        efx_oword_t reg;
 
        efx_reado(efx, &reg, FR_AZ_RX_CFG);
-       if (falcon_rev(efx) <= FALCON_REV_A1) {
+       if (efx_nic_rev(efx) <= EFX_REV_FALCON_A1) {
                /* Data FIFO size is 5.5K */
                if (data_xon_thr < 0)
                        data_xon_thr = 512 >> 8;
@@ -2958,6 +3021,9 @@ static void falcon_init_rx_cfg(struct efx_nic *efx)
                EFX_SET_OWORD_FIELD(reg, FRF_BZ_RX_XOFF_TX_TH, ctrl_xoff_thr);
                EFX_SET_OWORD_FIELD(reg, FRF_BZ_RX_INGR_EN, 1);
        }
+       /* Always enable XOFF signal from RX FIFO.  We enable
+        * or disable transmission of pause frames at the MAC. */
+       EFX_SET_OWORD_FIELD(reg, FRF_AZ_RX_XOFF_MAC_EN, 1);
        efx_writeo(efx, &reg, FR_AZ_RX_CFG);
 }
 
@@ -2965,7 +3031,7 @@ static void falcon_init_rx_cfg(struct efx_nic *efx)
  * defining the descriptor cache sizes and number of RSS channels.
  * It does not set up any buffers, descriptor rings or event queues.
  */
-int falcon_init_nic(struct efx_nic *efx)
+static int falcon_init_nic(struct efx_nic *efx)
 {
        efx_oword_t temp;
        int rc;
@@ -2976,20 +3042,25 @@ int falcon_init_nic(struct efx_nic *efx)
        efx_writeo(efx, &temp, FR_AB_NIC_STAT);
 
        /* Set the source of the GMAC clock */
-       if (falcon_rev(efx) == FALCON_REV_B0) {
+       if (efx_nic_rev(efx) == EFX_REV_FALCON_B0) {
                efx_reado(efx, &temp, FR_AB_GPIO_CTL);
                EFX_SET_OWORD_FIELD(temp, FRF_AB_USE_NIC_CLK, true);
                efx_writeo(efx, &temp, FR_AB_GPIO_CTL);
        }
 
+       /* Select the correct MAC */
+       falcon_clock_mac(efx);
+
        rc = falcon_reset_sram(efx);
        if (rc)
                return rc;
 
        /* Set positions of descriptor caches in SRAM. */
-       EFX_POPULATE_OWORD_1(temp, FRF_AZ_SRM_TX_DC_BASE_ADR, TX_DC_BASE / 8);
+       EFX_POPULATE_OWORD_1(temp, FRF_AZ_SRM_TX_DC_BASE_ADR,
+                            efx->type->tx_dc_base / 8);
        efx_writeo(efx, &temp, FR_AZ_SRM_TX_DC_CFG);
-       EFX_POPULATE_OWORD_1(temp, FRF_AZ_SRM_RX_DC_BASE_ADR, RX_DC_BASE / 8);
+       EFX_POPULATE_OWORD_1(temp, FRF_AZ_SRM_RX_DC_BASE_ADR,
+                            efx->type->rx_dc_base / 8);
        efx_writeo(efx, &temp, FR_AZ_SRM_RX_DC_CFG);
 
        /* Set TX descriptor cache size. */
@@ -3006,6 +3077,13 @@ int falcon_init_nic(struct efx_nic *efx)
        EFX_POPULATE_OWORD_1(temp, FRF_AZ_RX_DC_PF_LWM, RX_DC_ENTRIES - 8);
        efx_writeo(efx, &temp, FR_AZ_RX_DC_PF_WM);
 
+       /* Program INT_KER address */
+       EFX_POPULATE_OWORD_2(temp,
+                            FRF_AZ_NORM_INT_VEC_DIS_KER,
+                            EFX_INT_MODE_USE_MSI(efx),
+                            FRF_AZ_INT_ADR_KER, efx->irq_status.dma_addr);
+       efx_writeo(efx, &temp, FR_AZ_INT_ADR_KER);
+
        /* Clear the parity enables on the TX data fifos as
         * they produce false parity errors because of timing issues
         */
@@ -3064,7 +3142,7 @@ int falcon_init_nic(struct efx_nic *efx)
        /* Prefetch threshold 2 => fetch when descriptor cache half empty */
        EFX_SET_OWORD_FIELD(temp, FRF_AZ_TX_PREF_THRESHOLD, 2);
        /* Squash TX of packets of 16 bytes or less */
-       if (falcon_rev(efx) >= FALCON_REV_B0 && EFX_WORKAROUND_9141(efx))
+       if (efx_nic_rev(efx) >= EFX_REV_FALCON_B0)
                EFX_SET_OWORD_FIELD(temp, FRF_BZ_TX_FLUSH_MIN_LEN_EN, 1);
        efx_writeo(efx, &temp, FR_AZ_TX_RESERVED);
 
@@ -3078,7 +3156,7 @@ int falcon_init_nic(struct efx_nic *efx)
        falcon_init_rx_cfg(efx);
 
        /* Set destination of both TX and RX Flush events */
-       if (falcon_rev(efx) >= FALCON_REV_B0) {
+       if (efx_nic_rev(efx) >= EFX_REV_FALCON_B0) {
                EFX_POPULATE_OWORD_1(temp, FRF_BZ_FLS_EVQ_ID, 0);
                efx_writeo(efx, &temp, FR_BZ_DP_CTRL);
        }
@@ -3086,7 +3164,7 @@ int falcon_init_nic(struct efx_nic *efx)
        return 0;
 }
 
-void falcon_remove_nic(struct efx_nic *efx)
+static void falcon_remove_nic(struct efx_nic *efx)
 {
        struct falcon_nic_data *nic_data = efx->nic_data;
        struct falcon_board *board = falcon_board(efx);
@@ -3115,13 +3193,86 @@ void falcon_remove_nic(struct efx_nic *efx)
        efx->nic_data = NULL;
 }
 
-void falcon_update_nic_stats(struct efx_nic *efx)
+static void falcon_update_nic_stats(struct efx_nic *efx)
 {
+       struct falcon_nic_data *nic_data = efx->nic_data;
        efx_oword_t cnt;
 
+       if (nic_data->stats_disable_count)
+               return;
+
        efx_reado(efx, &cnt, FR_AZ_RX_NODESC_DROP);
        efx->n_rx_nodesc_drop_cnt +=
                EFX_OWORD_FIELD(cnt, FRF_AB_RX_NODESC_DROP_CNT);
+
+       if (nic_data->stats_pending &&
+           *nic_data->stats_dma_done == FALCON_STATS_DONE) {
+               nic_data->stats_pending = false;
+               rmb(); /* read the done flag before the stats */
+               efx->mac_op->update_stats(efx);
+       }
+}
+
+void falcon_start_nic_stats(struct efx_nic *efx)
+{
+       struct falcon_nic_data *nic_data = efx->nic_data;
+
+       spin_lock_bh(&efx->stats_lock);
+       if (--nic_data->stats_disable_count == 0)
+               falcon_stats_request(efx);
+       spin_unlock_bh(&efx->stats_lock);
+}
+
+void falcon_stop_nic_stats(struct efx_nic *efx)
+{
+       struct falcon_nic_data *nic_data = efx->nic_data;
+       int i;
+
+       might_sleep();
+
+       spin_lock_bh(&efx->stats_lock);
+       ++nic_data->stats_disable_count;
+       spin_unlock_bh(&efx->stats_lock);
+
+       del_timer_sync(&nic_data->stats_timer);
+
+       /* Wait enough time for the most recent transfer to
+        * complete. */
+       for (i = 0; i < 4 && nic_data->stats_pending; i++) {
+               if (*nic_data->stats_dma_done == FALCON_STATS_DONE)
+                       break;
+               msleep(1);
+       }
+
+       spin_lock_bh(&efx->stats_lock);
+       falcon_stats_complete(efx);
+       spin_unlock_bh(&efx->stats_lock);
+}
+
+static void falcon_set_id_led(struct efx_nic *efx, enum efx_led_mode mode)
+{
+       falcon_board(efx)->type->set_id_led(efx, mode);
+}
+
+/**************************************************************************
+ *
+ * Wake on LAN
+ *
+ **************************************************************************
+ */
+
+static void falcon_get_wol(struct efx_nic *efx, struct ethtool_wolinfo *wol)
+{
+       wol->supported = 0;
+       wol->wolopts = 0;
+       memset(&wol->sopass, 0, sizeof(wol->sopass));
+}
+
+static int falcon_set_wol(struct efx_nic *efx, u32 type)
+{
+       if (type != 0)
+               return -EINVAL;
+       return 0;
 }
 
 /**************************************************************************
@@ -3131,7 +3282,30 @@ void falcon_update_nic_stats(struct efx_nic *efx)
  **************************************************************************
  */
 
-struct efx_nic_type falcon_a_nic_type = {
+struct efx_nic_type falcon_a1_nic_type = {
+       .probe = falcon_probe_nic,
+       .remove = falcon_remove_nic,
+       .init = falcon_init_nic,
+       .fini = efx_port_dummy_op_void,
+       .monitor = falcon_monitor,
+       .reset = falcon_reset_hw,
+       .probe_port = falcon_probe_port,
+       .remove_port = falcon_remove_port,
+       .prepare_flush = falcon_prepare_flush,
+       .update_stats = falcon_update_nic_stats,
+       .start_stats = falcon_start_nic_stats,
+       .stop_stats = falcon_stop_nic_stats,
+       .set_id_led = falcon_set_id_led,
+       .push_irq_moderation = falcon_push_irq_moderation,
+       .push_multicast_hash = falcon_push_multicast_hash,
+       .reconfigure_port = falcon_reconfigure_port,
+       .get_wol = falcon_get_wol,
+       .set_wol = falcon_set_wol,
+       .resume_wol = efx_port_dummy_op_void,
+       .test_nvram = falcon_test_nvram,
+       .default_mac_ops = &falcon_xmac_operations,
+
+       .revision = EFX_REV_FALCON_A1,
        .mem_map_size = 0x20000,
        .txd_ptr_tbl_base = FR_AA_TX_DESC_PTR_TBL_KER,
        .rxd_ptr_tbl_base = FR_AA_RX_DESC_PTR_TBL_KER,
@@ -3142,9 +3316,36 @@ struct efx_nic_type falcon_a_nic_type = {
        .rx_buffer_padding = 0x24,
        .max_interrupt_mode = EFX_INT_MODE_MSI,
        .phys_addr_channels = 4,
+       .tx_dc_base = 0x130000,
+       .rx_dc_base = 0x100000,
+       .reset_world_flags = ETH_RESET_IRQ,
 };
 
-struct efx_nic_type falcon_b_nic_type = {
+struct efx_nic_type falcon_b0_nic_type = {
+       .probe = falcon_probe_nic,
+       .remove = falcon_remove_nic,
+       .init = falcon_init_nic,
+       .fini = efx_port_dummy_op_void,
+       .monitor = falcon_monitor,
+       .reset = falcon_reset_hw,
+       .probe_port = falcon_probe_port,
+       .remove_port = falcon_remove_port,
+       .prepare_flush = falcon_prepare_flush,
+       .update_stats = falcon_update_nic_stats,
+       .start_stats = falcon_start_nic_stats,
+       .stop_stats = falcon_stop_nic_stats,
+       .set_id_led = falcon_set_id_led,
+       .push_irq_moderation = falcon_push_irq_moderation,
+       .push_multicast_hash = falcon_push_multicast_hash,
+       .reconfigure_port = falcon_reconfigure_port,
+       .get_wol = falcon_get_wol,
+       .set_wol = falcon_set_wol,
+       .resume_wol = efx_port_dummy_op_void,
+       .test_registers = falcon_b0_test_registers,
+       .test_nvram = falcon_test_nvram,
+       .default_mac_ops = &falcon_xmac_operations,
+
+       .revision = EFX_REV_FALCON_B0,
        /* Map everything up to and including the RSS indirection
         * table.  Don't map MSI-X table, MSI-X PBA since Linux
         * requires that they not be mapped.  */
@@ -3162,5 +3363,8 @@ struct efx_nic_type falcon_b_nic_type = {
        .phys_addr_channels = 32, /* Hardware limit is 64, but the legacy
                                   * interrupt handler only supports 32
                                   * channels */
+       .tx_dc_base = 0x130000,
+       .rx_dc_base = 0x100000,
+       .reset_world_flags = ETH_RESET_IRQ,
 };