bce: Add workaround for the lost of MSI on 5706/5708
authorSepherosa Ziehau <sephe@dragonflybsd.org>
Wed, 28 Dec 2011 14:44:08 +0000 (22:44 +0800)
committerSepherosa Ziehau <sephe@dragonflybsd.org>
Wed, 28 Dec 2011 14:44:08 +0000 (22:44 +0800)
While I'm here use ramn_get_cpuid to extract interrupt's target CPU

Obtained-from: bnx2

sys/dev/netif/bce/if_bce.c
sys/dev/netif/bce/if_bcereg.h

index 0ade256..b07bbfd 100644 (file)
@@ -445,6 +445,7 @@ static void bce_stats_update(struct bce_softc *);
 static void    bce_tick(void *);
 static void    bce_tick_serialized(struct bce_softc *);
 static void    bce_pulse(void *);
+static void    bce_pulse_check_msi(struct bce_softc *);
 static void    bce_add_sysctls(struct bce_softc *);
 
 static void    bce_coal_change(struct bce_softc *);
@@ -970,7 +971,7 @@ bce_attach(device_t dev)
                goto fail;
        }
 
-       ifp->if_cpuid = ithread_cpuid(rman_get_start(sc->bce_res_irq));
+       ifp->if_cpuid = rman_get_cpuid(sc->bce_res_irq);
        KKASSERT(ifp->if_cpuid >= 0 && ifp->if_cpuid < ncpus);
 
        /* Print some important debugging info. */
@@ -3628,6 +3629,8 @@ bce_blockinit(struct bce_softc *sc)
        sc->last_status_idx = 0;
        sc->rx_mode = BCE_EMAC_RX_MODE_SORT_MODE;
 
+       sc->pulse_check_status_idx = 0xffff;
+
        /* Set up link change interrupt generation. */
        REG_WR(sc, BCE_EMAC_ATTENTION_ENA, BCE_EMAC_ATTENTION_ENA_LINK);
 
@@ -5862,6 +5865,12 @@ bce_pulse(void *xsc)
 
        lwkt_serialize_enter(ifp->if_serializer);
 
+       if (ifp->if_flags & IFF_RUNNING) {
+               if (sc->bce_irq_type == PCI_INTR_TYPE_MSI &&
+                   (sc->bce_flags & BCE_ONESHOT_MSI_FLAG) == 0)
+                       bce_pulse_check_msi(sc);
+       }
+
        /* Tell the firmware that the driver is still running. */
        msg = (uint32_t)++sc->bce_fw_drv_pulse_wr_seq;
        bce_shmem_wr(sc, BCE_DRV_PULSE_MB, msg);
@@ -5896,6 +5905,42 @@ bce_pulse(void *xsc)
        lwkt_serialize_exit(ifp->if_serializer);
 }
 
+static void
+bce_pulse_check_msi(struct bce_softc *sc)
+{
+       int check = 0;
+
+       if (bce_get_hw_rx_cons(sc) != sc->hw_rx_cons) {
+               check = 1;
+       } else if (bce_get_hw_tx_cons(sc) != sc->hw_tx_cons) {
+               check = 1;
+       } else {
+               struct status_block *sblk = sc->status_block;
+
+               if ((sblk->status_attn_bits & STATUS_ATTN_BITS_LINK_STATE) !=
+                   (sblk->status_attn_bits_ack & STATUS_ATTN_BITS_LINK_STATE))
+                       check = 1;
+       }
+
+       if (check) {
+               uint32_t msi_ctrl;
+
+               msi_ctrl = REG_RD(sc, BCE_PCICFG_MSI_CONTROL);
+               if ((msi_ctrl & BCE_PCICFG_MSI_CONTROL_ENABLE) == 0)
+                       return;
+
+               if (sc->pulse_check_status_idx == sc->last_status_idx) {
+                       if_printf(&sc->arpcom.ac_if, "missing MSI\n");
+
+                       REG_WR(sc, BCE_PCICFG_MSI_CONTROL,
+                           msi_ctrl & ~BCE_PCICFG_MSI_CONTROL_ENABLE);
+                       REG_WR(sc, BCE_PCICFG_MSI_CONTROL, msi_ctrl);
+
+                       bce_intr_msi(sc);
+               }
+       }
+       sc->pulse_check_status_idx = sc->last_status_idx;
+}
 
 /****************************************************************************/
 /* Periodic function to perform maintenance tasks.                          */
index 85c316f..015955f 100644 (file)
@@ -1059,6 +1059,9 @@ struct l2_fhdr {
  *  pci_config_l definition
  *  offset: 0000
  */
+#define BCE_PCICFG_MSI_CONTROL                         0x00000058
+#define BCE_PCICFG_MSI_CONTROL_ENABLE                   (1L<<16)
+
 #define BCE_PCICFG_MISC_CONFIG                         0x00000068
 #define BCE_PCICFG_MISC_CONFIG_TARGET_BYTE_SWAP                 (1L<<2)
 #define BCE_PCICFG_MISC_CONFIG_TARGET_MB_WORD_SWAP      (1L<<3)
@@ -5994,6 +5997,7 @@ struct bce_softc {
        bus_addr_t              status_block_paddr;     /* Physical address */
 
        /* Driver maintained status block values. */
+       uint16_t                pulse_check_status_idx;
        uint16_t                last_status_idx;
        uint16_t                hw_rx_cons;
        uint16_t                hw_tx_cons;