From 733403d618d2ba89c8c455033656c71b47d9e9b2 Mon Sep 17 00:00:00 2001 From: Sepherosa Ziehau Date: Wed, 28 Dec 2011 22:44:08 +0800 Subject: [PATCH] bce: Add workaround for the lost of MSI on 5706/5708 While I'm here use ramn_get_cpuid to extract interrupt's target CPU Obtained-from: bnx2 --- sys/dev/netif/bce/if_bce.c | 47 ++++++++++++++++++++++++++++++++++++++++- sys/dev/netif/bce/if_bcereg.h | 4 +++ 2 files changed, 50 insertions(+), 1 deletions(-) diff --git a/sys/dev/netif/bce/if_bce.c b/sys/dev/netif/bce/if_bce.c index 0ade256..b07bbfd 100644 --- a/sys/dev/netif/bce/if_bce.c +++ b/sys/dev/netif/bce/if_bce.c @@ -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. */ diff --git a/sys/dev/netif/bce/if_bcereg.h b/sys/dev/netif/bce/if_bcereg.h index 85c316f..015955f 100644 --- a/sys/dev/netif/bce/if_bcereg.h +++ b/sys/dev/netif/bce/if_bcereg.h @@ -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; -- 1.7.7.2