summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Speer <Michael.Speer@Sun.COM>2009-03-30 18:22:18 -0700
committerMichael Speer <Michael.Speer@Sun.COM>2009-03-30 18:22:18 -0700
commite759c33a51f9bc8c2bbf4f37e5ea7e7de77d8edc (patch)
tree92b458ca2159a2fd8a5ae1634eb49606c00a3094
parent8b2cc8ac894f2d58f38cf2fb7c3ac778f4c57c09 (diff)
downloadillumos-joyent-e759c33a51f9bc8c2bbf4f37e5ea7e7de77d8edc.tar.gz
6799252 nxge silently swallows interrupt when not initialized
-rw-r--r--usr/src/uts/common/io/nxge/nxge_hio_guest.c104
-rw-r--r--usr/src/uts/common/io/nxge/nxge_intr.c12
-rw-r--r--usr/src/uts/common/io/nxge/nxge_mac.c8
-rw-r--r--usr/src/uts/common/io/nxge/nxge_main.c136
-rw-r--r--usr/src/uts/common/io/nxge/nxge_rxdma.c72
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;
}