From: Sepherosa Ziehau Date: Sat, 18 Aug 2012 06:49:37 +0000 (+0800) Subject: bce: Rework MSI checkout for 5706 and 5708 X-Git-Tag: v3.2.0~366 X-Git-Url: http://gitweb.dragonflybsd.org/dragonfly.git/commitdiff_plain/28ef7645b9dc3a5cb7c206d3560b3a7262c972a6 bce: Rework MSI checkout for 5706 and 5708 --- diff --git a/sys/dev/netif/bce/if_bce.c b/sys/dev/netif/bce/if_bce.c index a352a34..0356404 100644 --- a/sys/dev/netif/bce/if_bce.c +++ b/sys/dev/netif/bce/if_bce.c @@ -94,6 +94,8 @@ #include #include +#define BCE_MSI_CKINTVL ((10 * hz) / 1000) /* 10ms */ + /****************************************************************************/ /* BCE Debug Options */ /****************************************************************************/ @@ -443,7 +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_check_msi(void *); static void bce_add_sysctls(struct bce_softc *); static void bce_coal_change(struct bce_softc *); @@ -754,10 +756,12 @@ bce_attach(device_t dev) if (sc->bce_irq_type == PCI_INTR_TYPE_LEGACY) { irq_handle = bce_intr_legacy; } else if (sc->bce_irq_type == PCI_INTR_TYPE_MSI) { - irq_handle = bce_intr_msi; if (BCE_CHIP_NUM(sc) == BCE_CHIP_NUM_5709) { irq_handle = bce_intr_msi_oneshot; sc->bce_flags |= BCE_ONESHOT_MSI_FLAG; + } else { + irq_handle = bce_intr_msi; + sc->bce_flags |= BCE_CHECK_MSI_FLAG; } } else { panic("%s: unsupported intr type %d", @@ -981,6 +985,7 @@ bce_attach(device_t dev) callout_init_mp(&sc->bce_tick_callout); callout_init_mp(&sc->bce_pulse_callout); + callout_init_mp(&sc->bce_ckmsi_callout); /* Hookup IRQ last. */ rc = bus_setup_intr(dev, sc->bce_res_irq, INTR_MPSAFE, irq_handle, sc, @@ -993,6 +998,7 @@ bce_attach(device_t dev) ifp->if_cpuid = rman_get_cpuid(sc->bce_res_irq); KKASSERT(ifp->if_cpuid >= 0 && ifp->if_cpuid < ncpus); + sc->bce_intr_cpuid = ifp->if_cpuid; /* Print some important debugging info. */ DBRUN(BCE_INFO, bce_dump_driver_state(sc)); @@ -3708,8 +3714,6 @@ 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); @@ -4641,6 +4645,13 @@ bce_disable_intr(struct bce_softc *sc) { REG_WR(sc, BCE_PCICFG_INT_ACK_CMD, BCE_PCICFG_INT_ACK_CMD_MASK_INT); REG_RD(sc, BCE_PCICFG_INT_ACK_CMD); + + callout_stop(&sc->bce_ckmsi_callout); + sc->bce_msi_maylose = FALSE; + sc->bce_check_rx_cons = 0; + sc->bce_check_tx_cons = 0; + sc->bce_check_status_idx = 0xffff; + lwkt_serialize_handler_disable(sc->arpcom.ac_if.if_serializer); } @@ -4663,6 +4674,19 @@ bce_enable_intr(struct bce_softc *sc) BCE_PCICFG_INT_ACK_CMD_INDEX_VALID | sc->last_status_idx); REG_WR(sc, BCE_HC_COMMAND, sc->hc_command | BCE_HC_COMMAND_COAL_NOW); + + if (sc->bce_flags & BCE_CHECK_MSI_FLAG) { + sc->bce_msi_maylose = FALSE; + sc->bce_check_rx_cons = 0; + sc->bce_check_tx_cons = 0; + sc->bce_check_status_idx = 0xffff; + + if (bootverbose) + if_printf(&sc->arpcom.ac_if, "check msi\n"); + + callout_reset_bycpu(&sc->bce_ckmsi_callout, BCE_MSI_CKINTVL, + bce_check_msi, sc, sc->bce_intr_cpuid); + } } @@ -4684,6 +4708,7 @@ bce_reenable_intr(struct bce_softc *sc) BCE_PCICFG_INT_ACK_CMD_INDEX_VALID | sc->last_status_idx); } + /****************************************************************************/ /* Handles controller initialization. */ /* */ @@ -5725,12 +5750,6 @@ 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); @@ -5765,43 +5784,71 @@ bce_pulse(void *xsc) lwkt_serialize_exit(ifp->if_serializer); } + +/****************************************************************************/ +/* Periodic function to check whether MSI is lost */ +/* */ +/* Returns: */ +/* Nothing. */ +/****************************************************************************/ static void -bce_pulse_check_msi(struct bce_softc *sc) +bce_check_msi(void *xsc) { - int check = 0; + struct bce_softc *sc = xsc; + struct ifnet *ifp = &sc->arpcom.ac_if; + struct status_block *sblk = sc->status_block; - if (bce_get_hw_rx_cons(sc) != sc->rx_cons) { - check = 1; - } else if (bce_get_hw_tx_cons(sc) != sc->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; - } + lwkt_serialize_enter(ifp->if_serializer); - if (check) { - uint32_t msi_ctrl; + KKASSERT(mycpuid == sc->bce_intr_cpuid); - msi_ctrl = REG_RD(sc, BCE_PCICFG_MSI_CONTROL); - if ((msi_ctrl & BCE_PCICFG_MSI_CONTROL_ENABLE) == 0) - return; + if ((ifp->if_flags & (IFF_RUNNING | IFF_POLLING)) != IFF_RUNNING) { + lwkt_serialize_exit(ifp->if_serializer); + return; + } + + if (bce_get_hw_rx_cons(sc) != sc->rx_cons || + bce_get_hw_tx_cons(sc) != sc->tx_cons || + (sblk->status_attn_bits & STATUS_ATTN_BITS_LINK_STATE) != + (sblk->status_attn_bits_ack & STATUS_ATTN_BITS_LINK_STATE)) { + if (sc->bce_check_rx_cons == sc->rx_cons && + sc->bce_check_tx_cons == sc->tx_cons && + sc->bce_check_status_idx == sc->last_status_idx) { + uint32_t msi_ctrl; + + if (!sc->bce_msi_maylose) { + sc->bce_msi_maylose = TRUE; + goto done; + } - if (sc->pulse_check_status_idx == sc->last_status_idx) { - if_printf(&sc->arpcom.ac_if, "missing MSI\n"); + msi_ctrl = REG_RD(sc, BCE_PCICFG_MSI_CONTROL); + if (msi_ctrl & BCE_PCICFG_MSI_CONTROL_ENABLE) { + if (bootverbose) + if_printf(ifp, "lost 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); + 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); + bce_intr_msi(sc); + } else if (bootverbose) { + if_printf(ifp, "MSI may be lost\n"); + } } } - sc->pulse_check_status_idx = sc->last_status_idx; + sc->bce_msi_maylose = FALSE; + sc->bce_check_rx_cons = sc->rx_cons; + sc->bce_check_tx_cons = sc->tx_cons; + sc->bce_check_status_idx = sc->last_status_idx; + +done: + callout_reset(&sc->bce_ckmsi_callout, BCE_MSI_CKINTVL, + bce_check_msi, sc); + lwkt_serialize_exit(ifp->if_serializer); } + /****************************************************************************/ /* 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 cd06cf1..b2ec82c 100644 --- a/sys/dev/netif/bce/if_bcereg.h +++ b/sys/dev/netif/bce/if_bcereg.h @@ -5873,6 +5873,7 @@ struct bce_softc { uint32_t bce_flags; #define BCE_PCIX_FLAG 0x00000001 #define BCE_PCI_32BIT_FLAG 0x00000002 +#define BCE_CHECK_MSI_FLAG 0x00000004 #define BCE_NO_WOL_FLAG 0x00000008 #define BCE_USING_DAC_FLAG 0x00000010 #define BCE_MFW_ENABLE_FLAG 0x00000040 /* Management F/W is enabled */ @@ -5968,10 +5969,17 @@ struct bce_softc { uint16_t tx_cons; uint32_t tx_prod_bseq; /* Counts the bytes used. */ + int bce_intr_cpuid; int bce_link; struct callout bce_tick_callout; struct callout bce_pulse_callout; + boolean_t bce_msi_maylose; + uint16_t bce_check_rx_cons; + uint16_t bce_check_tx_cons; + uint16_t bce_check_status_idx; + struct callout bce_ckmsi_callout; + /* Frame size and mbuf allocation size for RX frames. */ uint32_t max_frame_size; int mbuf_alloc_size; @@ -6001,7 +6009,6 @@ 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; /* H/W maintained statistics block. */