diff options
author | Michael Speer <Michael.Speer@Sun.COM> | 2009-03-30 18:22:18 -0700 |
---|---|---|
committer | Michael Speer <Michael.Speer@Sun.COM> | 2009-03-30 18:22:18 -0700 |
commit | e759c33a51f9bc8c2bbf4f37e5ea7e7de77d8edc (patch) | |
tree | 92b458ca2159a2fd8a5ae1634eb49606c00a3094 | |
parent | 8b2cc8ac894f2d58f38cf2fb7c3ac778f4c57c09 (diff) | |
download | illumos-joyent-e759c33a51f9bc8c2bbf4f37e5ea7e7de77d8edc.tar.gz |
6799252 nxge silently swallows interrupt when not initialized
-rw-r--r-- | usr/src/uts/common/io/nxge/nxge_hio_guest.c | 104 | ||||
-rw-r--r-- | usr/src/uts/common/io/nxge/nxge_intr.c | 12 | ||||
-rw-r--r-- | usr/src/uts/common/io/nxge/nxge_mac.c | 8 | ||||
-rw-r--r-- | usr/src/uts/common/io/nxge/nxge_main.c | 136 | ||||
-rw-r--r-- | usr/src/uts/common/io/nxge/nxge_rxdma.c | 72 |
5 files changed, 284 insertions, 48 deletions
diff --git a/usr/src/uts/common/io/nxge/nxge_hio_guest.c b/usr/src/uts/common/io/nxge/nxge_hio_guest.c index 5517b9ceee..5d433b7391 100644 --- a/usr/src/uts/common/io/nxge/nxge_hio_guest.c +++ b/usr/src/uts/common/io/nxge/nxge_hio_guest.c @@ -20,7 +20,7 @@ */ /* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -964,4 +964,106 @@ nxge_check_guest_state_exit: NXGE_DEBUG_MSG((nxge, SYSERR_CTL, "<== nxge_check_guest_state")); } +nxge_status_t +nxge_hio_rdc_intr_arm(p_nxge_t nxge, boolean_t arm) +{ + nxge_grp_t *group; + uint32_t channel; + nxge_hio_dc_t *dc; + nxge_ldg_t *ldgp; + + /* + * Validate state of guest interface before + * proceeeding. + */ + if (!isLDOMguest(nxge)) + return (NXGE_ERROR); + if (nxge->nxge_mac_state != NXGE_MAC_STARTED) + return (NXGE_ERROR); + + /* + * In guest domain, always and only dealing with + * group 0 for an instance of nxge. + */ + group = nxge->rx_set.group[0]; + + /* + * Look to arm the the RDCs for the group. + */ + for (channel = 0; channel < NXGE_MAX_RDCS; channel++) { + if ((1 << channel) & group->map) { + /* + * Get the RDC. + */ + dc = nxge_grp_dc_find(nxge, VP_BOUND_RX, channel); + if (dc == NULL) + return (NXGE_ERROR); + + /* + * Get the RDC's ldg group. + */ + ldgp = &nxge->ldgvp->ldgp[dc->ldg.vector]; + if (ldgp == NULL) + return (NXGE_ERROR); + + /* + * Set the state of the group. + */ + ldgp->arm = arm; + + nxge_hio_ldgimgn(nxge, ldgp); + } + } + + return (NXGE_OK); +} + +nxge_status_t +nxge_hio_rdc_enable(p_nxge_t nxge) +{ + nxge_grp_t *group; + npi_handle_t handle; + uint32_t channel; + npi_status_t rval; + + /* + * Validate state of guest interface before + * proceeeding. + */ + if (!isLDOMguest(nxge)) + return (NXGE_ERROR); + if (nxge->nxge_mac_state != NXGE_MAC_STARTED) + return (NXGE_ERROR); + + /* + * In guest domain, always and only dealing with + * group 0 for an instance of nxge. + */ + group = nxge->rx_set.group[0]; + + /* + * Get the PIO handle. + */ + handle = NXGE_DEV_NPI_HANDLE(nxge); + + for (channel = 0; channel < NXGE_MAX_RDCS; channel++) { + /* + * If this channel is in the map, then enable + * it. + */ + if ((1 << channel) & group->map) { + /* + * Enable the RDC and clear the empty bit. + */ + rval = npi_rxdma_cfg_rdc_enable(handle, channel); + if (rval != NPI_SUCCESS) + return (NXGE_ERROR); + + (void) npi_rxdma_channel_rbr_empty_clear(handle, + channel); + } + } + + return (NXGE_OK); +} #endif /* defined(sun4v) */ diff --git a/usr/src/uts/common/io/nxge/nxge_intr.c b/usr/src/uts/common/io/nxge/nxge_intr.c index adc440f596..9c50981c34 100644 --- a/usr/src/uts/common/io/nxge/nxge_intr.c +++ b/usr/src/uts/common/io/nxge/nxge_intr.c @@ -20,7 +20,7 @@ */ /* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -381,8 +381,14 @@ nxge_hio_intr_add( interrupts->intr_enabled = B_TRUE; - /* Finally, arm the interrupt. */ - nxge_hio_ldgimgn(nxge, group); + /* + * Note: RDC interrupts will be armed in nxge_m_start(). This + * prevents us from getting an interrupt before we are ready + * to process packets. + */ + if (type == VP_BOUND_TX) { + nxge_hio_ldgimgn(nxge, group); + } dc->interrupting = B_TRUE; diff --git a/usr/src/uts/common/io/nxge/nxge_mac.c b/usr/src/uts/common/io/nxge/nxge_mac.c index 8ca60cf7a7..68041496ff 100644 --- a/usr/src/uts/common/io/nxge/nxge_mac.c +++ b/usr/src/uts/common/io/nxge/nxge_mac.c @@ -19,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -909,8 +909,10 @@ nxge_mac_init(p_nxge_t nxgep) if ((status = nxge_tx_mac_enable(nxgep)) != NXGE_OK) goto fail; - if ((status = nxge_rx_mac_enable(nxgep)) != NXGE_OK) - goto fail; + if (nxgep->nxge_mac_state == NXGE_MAC_STARTED) { + if ((status = nxge_rx_mac_enable(nxgep)) != NXGE_OK) + goto fail; + } /* Initialize MAC control configuration */ if ((status = nxge_mac_ctrl_init(nxgep)) != NXGE_OK) { diff --git a/usr/src/uts/common/io/nxge/nxge_main.c b/usr/src/uts/common/io/nxge/nxge_main.c index 2708bcfe44..a8e16afdc3 100644 --- a/usr/src/uts/common/io/nxge/nxge_main.c +++ b/usr/src/uts/common/io/nxge/nxge_main.c @@ -259,6 +259,10 @@ static int nxge_init_common_dev(p_nxge_t); static void nxge_uninit_common_dev(p_nxge_t); extern int nxge_param_set_mac(p_nxge_t, queue_t *, mblk_t *, char *, caddr_t); +#if defined(sun4v) +extern nxge_status_t nxge_hio_rdc_enable(p_nxge_t nxgep); +extern nxge_status_t nxge_hio_rdc_intr_arm(p_nxge_t nxge, boolean_t arm); +#endif /* * The next declarations are for the GLDv3 interface. @@ -1627,12 +1631,11 @@ nxge_init(p_nxge_t nxgep) goto nxge_init_fail5; } - nxge_intrs_enable(nxgep); /* XXX What changes do I need to make here? */ - /* - * Enable hardware interrupts. + * Enable the interrrupts for DDI. */ - nxge_intr_hw_enable(nxgep); + nxge_intrs_enable(nxgep); + nxgep->drv_state |= STATE_HW_INITIALIZED; goto nxge_init_exit; @@ -1691,6 +1694,18 @@ nxge_uninit(p_nxge_t nxgep) return; } + if (!isLDOMguest(nxgep)) { + /* + * Reset the receive MAC side. + */ + (void) nxge_rx_mac_disable(nxgep); + + /* + * Drain the IPP. + */ + (void) nxge_ipp_drain(nxgep); + } + /* stop timer */ if (nxgep->nxge_timerid) { nxge_stop_timer(nxgep, nxgep->nxge_timerid); @@ -1700,10 +1715,6 @@ nxge_uninit(p_nxge_t nxgep) (void) nxge_link_monitor(nxgep, LINK_MONITOR_STOP); (void) nxge_intr_hw_disable(nxgep); - /* - * Reset the receive MAC side. - */ - (void) nxge_rx_mac_disable(nxgep); /* Disable and soft reset the IPP */ if (!isLDOMguest(nxgep)) @@ -3687,11 +3698,32 @@ nxge_m_start(void *arg) NXGE_DEBUG_MSG((nxgep, NXGE_CTL, "==> nxge_m_start")); + /* + * Are we already started? + */ + if (nxgep->nxge_mac_state == NXGE_MAC_STARTED) { + return (0); + } + if (nxge_peu_reset_enable && !nxgep->nxge_link_poll_timerid) { (void) nxge_link_monitor(nxgep, LINK_MONITOR_START); } + /* + * Make sure RX MAC is disabled while we initialize. + */ + if (!isLDOMguest(nxgep)) { + (void) nxge_rx_mac_disable(nxgep); + } + + /* + * Grab the global lock. + */ MUTEX_ENTER(nxgep->genlock); + + /* + * Initialize the driver and hardware. + */ if (nxge_init(nxgep) != NXGE_OK) { NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL, "<== nxge_m_start: initialization failed")); @@ -3699,30 +3731,64 @@ nxge_m_start(void *arg) return (EIO); } - if (nxgep->nxge_mac_state == NXGE_MAC_STARTED) - goto nxge_m_start_exit; /* * Start timer to check the system error and tx hangs */ if (!isLDOMguest(nxgep)) nxgep->nxge_timerid = nxge_start_timer(nxgep, nxge_check_hw_state, NXGE_CHECK_TIMER); -#if defined(sun4v) +#if defined(sun4v) else nxge_hio_start_timer(nxgep); #endif nxgep->link_notify = B_TRUE; - nxgep->nxge_mac_state = NXGE_MAC_STARTED; -nxge_m_start_exit: + /* + * Let the global lock go, since we are intialized. + */ MUTEX_EXIT(nxgep->genlock); + + /* + * Let the MAC start receiving packets, now that + * we are initialized. + */ + if (!isLDOMguest(nxgep)) { + if (nxge_rx_mac_enable(nxgep) != NXGE_OK) { + NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL, + "<== nxge_m_start: enable of RX mac failed")); + return (EIO); + } + + /* + * Enable hardware interrupts. + */ + nxge_intr_hw_enable(nxgep); + } +#if defined(sun4v) + else { + /* + * In guest domain we enable RDCs and their interrupts as + * the last step. + */ + if (nxge_hio_rdc_enable(nxgep) != NXGE_OK) { + NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL, + "<== nxge_m_start: enable of RDCs failed")); + return (EIO); + } + + if (nxge_hio_rdc_intr_arm(nxgep, B_TRUE) != NXGE_OK) { + NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL, + "<== nxge_m_start: intrs enable for RDCs failed")); + return (EIO); + } + } +#endif NXGE_DEBUG_MSG((nxgep, NXGE_CTL, "<== nxge_m_start")); return (0); } - static boolean_t nxge_check_groups_stopped(p_nxge_t nxgep) { @@ -3747,31 +3813,61 @@ nxge_m_stop(void *arg) NXGE_DEBUG_MSG((nxgep, NXGE_CTL, "==> nxge_m_stop")); + /* + * Are the groups stopped? + */ groups_stopped = nxge_check_groups_stopped(nxgep); -#ifdef later - ASSERT(groups_stopped == B_FALSE); -#endif - + ASSERT(groups_stopped == B_TRUE); if (!groups_stopped) { cmn_err(CE_WARN, "nxge(%d): groups are not stopped!\n", nxgep->instance); return; } + if (!isLDOMguest(nxgep)) { + /* + * Disable the RX mac. + */ + (void) nxge_rx_mac_disable(nxgep); + + /* + * Wait for the IPP to drain. + */ + (void) nxge_ipp_drain(nxgep); + + /* + * Disable hardware interrupts. + */ + nxge_intr_hw_disable(nxgep); + } +#if defined(sun4v) + else { + (void) nxge_hio_rdc_intr_arm(nxgep, B_FALSE); + } +#endif + + /* + * Grab the global lock. + */ MUTEX_ENTER(nxgep->genlock); - nxgep->nxge_mac_state = NXGE_MAC_STOPPING; + nxgep->nxge_mac_state = NXGE_MAC_STOPPING; if (nxgep->nxge_timerid) { nxge_stop_timer(nxgep, nxgep->nxge_timerid); nxgep->nxge_timerid = 0; } + /* + * Clean up. + */ nxge_uninit(nxgep); nxgep->nxge_mac_state = NXGE_MAC_STOPPED; + /* + * Let go of the global lock. + */ MUTEX_EXIT(nxgep->genlock); - NXGE_DEBUG_MSG((nxgep, NXGE_CTL, "<== nxge_m_stop")); } diff --git a/usr/src/uts/common/io/nxge/nxge_rxdma.c b/usr/src/uts/common/io/nxge/nxge_rxdma.c index d69007f922..1432a4a544 100644 --- a/usr/src/uts/common/io/nxge/nxge_rxdma.c +++ b/usr/src/uts/common/io/nxge/nxge_rxdma.c @@ -619,16 +619,21 @@ nxge_enable_rxdma_channel(p_nxge_t nxgep, uint16_t channel, return (NXGE_ERROR | rs); } - /* Enable the DMA */ - rs = npi_rxdma_cfg_rdc_enable(handle, channel); - if (rs != NPI_SUCCESS) { - return (NXGE_ERROR | rs); + if (!isLDOMguest(nxgep)) { + /* Enable the DMA */ + rs = npi_rxdma_cfg_rdc_enable(handle, channel); + if (rs != NPI_SUCCESS) { + return (NXGE_ERROR | rs); + } } /* Kick the DMA engine. */ npi_rxdma_rdc_rbr_kick(handle, channel, rbr_p->rbb_max); - /* Clear the rbr empty bit */ - (void) npi_rxdma_channel_rbr_empty_clear(handle, channel); + + if (!isLDOMguest(nxgep)) { + /* Clear the rbr empty bit */ + (void) npi_rxdma_channel_rbr_empty_clear(handle, channel); + } NXGE_DEBUG_MSG((nxgep, DMA_CTL, "<== nxge_enable_rxdma_channel")); @@ -1826,15 +1831,10 @@ nxge_rx_intr(void *arg1, void *arg2) p_rx_rcr_ring_t rcr_ring; mblk_t *mp; -#ifdef NXGE_DEBUG - rxdma_cfig1_t cfg; -#endif - if (ldvp == NULL) { NXGE_DEBUG_MSG((NULL, INT_CTL, "<== nxge_rx_intr: arg2 $%p arg1 $%p", nxgep, ldvp)); - return (DDI_INTR_CLAIMED); } @@ -1854,11 +1854,13 @@ nxge_rx_intr(void *arg1, void *arg2) nxgep, ldvp)); /* - * This interrupt handler is for a specific - * receive dma channel. + * Get the PIO handle. */ handle = NXGE_DEV_NPI_HANDLE(nxgep); + /* + * Get the ring to enable us to process packets. + */ rcr_ring = nxgep->rx_rcr_rings->rcr_rings[ldvp->vdma_index]; /* @@ -1877,13 +1879,41 @@ nxge_rx_intr(void *arg1, void *arg2) channel = ldvp->channel; ldgp = ldvp->ldgp; - if (!isLDOMguest(nxgep)) { - if (!nxgep->rx_channel_started[channel]) { - NXGE_DEBUG_MSG((nxgep, INT_CTL, - "<== nxge_rx_intr: channel is not started")); - MUTEX_EXIT(&rcr_ring->lock); - return (DDI_INTR_CLAIMED); + if (!isLDOMguest(nxgep) && (!nxgep->rx_channel_started[channel])) { + NXGE_DEBUG_MSG((nxgep, INT_CTL, + "<== nxge_rx_intr: channel is not started")); + + /* + * We received an interrupt before the ring is started. + */ + RXDMA_REG_READ64(handle, RX_DMA_CTL_STAT_REG, channel, + &cs.value); + cs.value &= RX_DMA_CTL_STAT_WR1C; + cs.bits.hdw.mex = 1; + RXDMA_REG_WRITE64(handle, RX_DMA_CTL_STAT_REG, channel, + cs.value); + + /* + * Rearm this logical group if this is a single device + * group. + */ + if (ldgp->nldvs == 1) { + if (isLDOMguest(nxgep)) { + nxge_hio_ldgimgn(nxgep, ldgp); + } else { + ldgimgm_t mgm; + + mgm.value = 0; + mgm.bits.ldw.arm = 1; + mgm.bits.ldw.timer = ldgp->ldg_timer; + + NXGE_REG_WR64(handle, + LDGIMGN_REG + LDSV_OFFSET(ldgp->ldg), + mgm.value); + } } + MUTEX_EXIT(&rcr_ring->lock); + return (DDI_INTR_CLAIMED); } ASSERT(rcr_ring->ldgp == ldgp); @@ -4975,8 +5005,8 @@ nxge_rxdma_databuf_free(p_rx_rbr_ring_t rbr_p) } if (rbr_p->rbr_alloc_type == DDI_MEM_ALLOC) { - NXGE_ERROR_MSG((NULL, NXGE_ERR_CTL, - "==> nxge_rxdma_databuf_free: DDI")); + NXGE_DEBUG_MSG((NULL, DMA_CTL, + "<== nxge_rxdma_databuf_free: DDI")); return; } |