summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authormx205022 <none@none>2008-01-21 01:32:31 -0800
committermx205022 <none@none>2008-01-21 01:32:31 -0800
commit2d58516de420814c8fd871526b0aaa3cd9fb9443 (patch)
tree52a4dd89872e6c849577e72f2bca445732a82d17
parent1b47e080b07ee427f2239a6564769802c9e5ac99 (diff)
downloadillumos-gate-2d58516de420814c8fd871526b0aaa3cd9fb9443.tar.gz
6637122 nge suspend/resume improvements
-rw-r--r--usr/src/uts/common/io/nge/nge_chip.c21
-rw-r--r--usr/src/uts/common/io/nge/nge_main.c138
2 files changed, 107 insertions, 52 deletions
diff --git a/usr/src/uts/common/io/nge/nge_chip.c b/usr/src/uts/common/io/nge/nge_chip.c
index 5f55e22a7c..aea886cb03 100644
--- a/usr/src/uts/common/io/nge/nge_chip.c
+++ b/usr/src/uts/common/io/nge/nge_chip.c
@@ -951,15 +951,12 @@ nge_chip_reset(nge_t *ngep)
uint32_t regno;
uint64_t mac;
nge_uni_addr1 uaddr1;
- nge_mul_addr1 maddr1;
nge_cp_cntl ee_cntl;
nge_soft_misc soft_misc;
nge_pmu_cntl0 pmu_cntl0;
nge_pmu_cntl2 pmu_cntl2;
nge_pm_cntl2 pm_cntl2;
const nge_ksindex_t *ksip;
- nge_sw_statistics_t *sw_stp;
- sw_stp = &ngep->statistics.sw_statistics;
NGE_TRACE(("nge_chip_reset($%p)", (void *)ngep));
@@ -970,19 +967,6 @@ nge_chip_reset(nge_t *ngep)
regno = KS_BASE + ksip->index * sizeof (uint32_t);
(void) nge_reg_get32(ngep, regno);
}
- /* Clear the software statistics */
- sw_stp->recv_count = 0;
- sw_stp->xmit_count = 0;
- sw_stp->rbytes = 0;
- sw_stp->obytes = 0;
-
- /*
- * Clear the Multicast mac address table
- */
- nge_reg_put32(ngep, NGE_MUL_ADDR0, 0);
- maddr1.addr_val = nge_reg_get32(ngep, NGE_MUL_ADDR1);
- maddr1.addr_bits.addr = 0;
- nge_reg_put32(ngep, NGE_MUL_ADDR1, maddr1.addr_val);
/*
* Setup seeprom control
@@ -1775,6 +1759,11 @@ nge_chip_intr(caddr_t arg1, caddr_t arg2)
mutex_enter(ngep->genlock);
+ if (ngep->suspended) {
+ mutex_exit(ngep->genlock);
+ return (DDI_INTR_UNCLAIMED);
+ }
+
/*
* Check whether chip's says it's asserting #INTA;
* if not, don't process or claim the interrupt.
diff --git a/usr/src/uts/common/io/nge/nge_main.c b/usr/src/uts/common/io/nge/nge_main.c
index e89cf7c7e0..11987c5742 100644
--- a/usr/src/uts/common/io/nge/nge_main.c
+++ b/usr/src/uts/common/io/nge/nge_main.c
@@ -20,7 +20,7 @@
*/
/*
- * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -1029,6 +1029,9 @@ static int
nge_reset(nge_t *ngep)
{
int err;
+ nge_mul_addr1 maddr1;
+ nge_sw_statistics_t *sw_stp;
+ sw_stp = &ngep->statistics.sw_statistics;
send_ring_t *srp = ngep->send;
ASSERT(mutex_owned(ngep->genlock));
@@ -1043,6 +1046,14 @@ nge_reset(nge_t *ngep)
return (err);
}
err = nge_chip_reset(ngep);
+ /*
+ * Clear the Multicast mac address table
+ */
+ nge_reg_put32(ngep, NGE_MUL_ADDR0, 0);
+ maddr1.addr_val = nge_reg_get32(ngep, NGE_MUL_ADDR1);
+ maddr1.addr_bits.addr = 0;
+ nge_reg_put32(ngep, NGE_MUL_ADDR1, maddr1.addr_val);
+
mutex_exit(srp->tx_lock);
mutex_exit(srp->tc_lock);
if (err == DDI_FAILURE)
@@ -1057,6 +1068,13 @@ nge_reset(nge_t *ngep)
ngep->max_sdu = ngep->default_mtu + ETHER_HEAD_LEN + ETHERFCSL;
ngep->max_sdu += VTAG_SIZE;
ngep->rx_def = 0x16;
+
+ /* Clear the software statistics */
+ sw_stp->recv_count = 0;
+ sw_stp->xmit_count = 0;
+ sw_stp->rbytes = 0;
+ sw_stp->obytes = 0;
+
return (DDI_SUCCESS);
}
@@ -1068,17 +1086,15 @@ nge_m_stop(void *arg)
NGE_TRACE(("nge_m_stop($%p)", arg));
/*
- * If suspended, adapter is already stopped, just return.
+ * Just stop processing, then record new MAC state
*/
+ mutex_enter(ngep->genlock);
+ /* If suspended, the adapter is already stopped, just return. */
if (ngep->suspended) {
ASSERT(ngep->nge_mac_state == NGE_MAC_STOPPED);
+ mutex_exit(ngep->genlock);
return;
}
-
- /*
- * Just stop processing, then record new MAC state
- */
- mutex_enter(ngep->genlock);
rw_enter(ngep->rwlock, RW_WRITER);
(void) nge_chip_stop(ngep, B_FALSE);
@@ -1103,16 +1119,19 @@ nge_m_start(void *arg)
nge_t *ngep = arg;
NGE_TRACE(("nge_m_start($%p)", arg));
+
+ /*
+ * Start processing and record new MAC state
+ */
+ mutex_enter(ngep->genlock);
/*
* If suspended, don't start, as the resume processing
* will recall this function with the suspended flag off.
*/
- if (ngep->suspended)
+ if (ngep->suspended) {
+ mutex_exit(ngep->genlock);
return (DDI_FAILURE);
- /*
- * Start processing and record new MAC state
- */
- mutex_enter(ngep->genlock);
+ }
rw_enter(ngep->rwlock, RW_WRITER);
err = nge_alloc_bufs(ngep);
if (err != DDI_SUCCESS) {
@@ -1155,9 +1174,10 @@ nge_m_unicst(void *arg, const uint8_t *macaddr)
* the chip. Doing so might put it in a bad state, but the
* resume will get the unicast address installed.
*/
- if (ngep->suspended)
+ if (ngep->suspended) {
+ mutex_exit(ngep->genlock);
return (DDI_SUCCESS);
-
+ }
nge_chip_sync(ngep);
NGE_DEBUG(("nge_m_unicst($%p) done", arg));
@@ -1172,17 +1192,20 @@ nge_m_promisc(void *arg, boolean_t on)
nge_t *ngep = arg;
NGE_TRACE(("nge_m_promisc($%p)", arg));
- /*
- * If suspended, we don't do anything, even record the promiscuious
- * mode, as we won't properly set it on resume. Just fail.
- */
- if (ngep->suspended)
- return (DDI_FAILURE);
/*
* Store specified mode and pass to chip layer to update h/w
*/
mutex_enter(ngep->genlock);
+ /*
+ * If suspended, there is no need to do anything, even
+ * recording the promiscuious mode is not neccessary, as
+ * it won't be properly set on resume. Just return failing.
+ */
+ if (ngep->suspended) {
+ mutex_exit(ngep->genlock);
+ return (DDI_FAILURE);
+ }
if (ngep->promisc == on) {
mutex_exit(ngep->genlock);
NGE_DEBUG(("nge_m_promisc($%p) done", arg));
@@ -1286,7 +1309,7 @@ nge_m_multicst(void *arg, boolean_t add, const uint8_t *mca)
}
}
- if (update || !ngep->suspended) {
+ if (update && !ngep->suspended) {
nge_mulparam(ngep);
nge_chip_sync(ngep);
}
@@ -1312,10 +1335,13 @@ nge_m_ioctl(void *arg, queue_t *wq, mblk_t *mp)
* without actually putting the hardware in an undesireable
* state. So just NAK it.
*/
+ mutex_enter(ngep->genlock);
if (ngep->suspended) {
miocnak(wq, mp, 0, EINVAL);
+ mutex_exit(ngep->genlock);
return;
}
+ mutex_exit(ngep->genlock);
/*
* Validate the command before bothering with the mutex ...
@@ -1497,8 +1523,9 @@ int
nge_restart(nge_t *ngep)
{
int err = 0;
- err += nge_reset(ngep);
- err += nge_chip_start(ngep);
+ err = nge_reset(ngep);
+ if (!err)
+ err = nge_chip_start(ngep);
if (err) {
ngep->nge_mac_state = NGE_MAC_STOPPED;
@@ -1623,10 +1650,13 @@ nge_resume(dev_info_t *devinfo)
{
nge_t *ngep;
chip_info_t *infop;
+ int err;
ASSERT(devinfo != NULL);
ngep = ddi_get_driver_private(devinfo);
+ err = 0;
+
/*
* If there are state inconsistancies, this is bad. Returning
* DDI_FAILURE here will eventually cause the machine to panic,
@@ -1640,9 +1670,10 @@ nge_resume(dev_info_t *devinfo)
if (ngep->devinfo != devinfo)
cmn_err(CE_PANIC,
- "nge: passed devinfo not the same as saved definfo");
+ "nge: passed devinfo not the same as saved devinfo");
- ngep->suspended = B_FALSE;
+ mutex_enter(ngep->genlock);
+ rw_enter(ngep->rwlock, RW_WRITER);
/*
* Fetch the config space. Even though we have most of it cached,
@@ -1651,16 +1682,37 @@ nge_resume(dev_info_t *devinfo)
nge_chip_cfg_init(ngep, infop, B_FALSE);
/*
- * Start the controller. In this case (and probably most GLDv3
- * devices), it is sufficient to call nge_m_start().
+ * Only in one case, this conditional branch can be executed: the port
+ * hasn't been plumbed.
*/
- if (nge_m_start((void *)ngep) != DDI_SUCCESS) {
+ if (ngep->suspended == B_FALSE) {
+ rw_exit(ngep->rwlock);
+ mutex_exit(ngep->genlock);
+ return (DDI_SUCCESS);
+ }
+
+ nge_tx_recycle_all(ngep);
+ err = nge_reinit_ring(ngep);
+ if (!err) {
+ err = nge_chip_reset(ngep);
+ if (!err)
+ err = nge_chip_start(ngep);
+ }
+
+ if (err) {
/*
* We note the failure, but return success, as the
* system is still usable without this controller.
*/
cmn_err(CE_WARN, "nge: resume: failed to restart controller");
+ } else {
+ ngep->nge_mac_state = NGE_MAC_STARTED;
}
+ ngep->suspended = B_FALSE;
+
+ rw_exit(ngep->rwlock);
+ mutex_exit(ngep->genlock);
+
return (DDI_SUCCESS);
}
@@ -1811,6 +1863,27 @@ attach_fail:
return (DDI_FAILURE);
}
+static int
+nge_suspend(nge_t *ngep)
+{
+ mutex_enter(ngep->genlock);
+ rw_enter(ngep->rwlock, RW_WRITER);
+
+ /* if the port hasn't been plumbed, just return */
+ if (ngep->nge_mac_state != NGE_MAC_STARTED) {
+ rw_exit(ngep->rwlock);
+ mutex_exit(ngep->genlock);
+ return (DDI_SUCCESS);
+ }
+ ngep->suspended = B_TRUE;
+ (void) nge_chip_stop(ngep, B_FALSE);
+ ngep->nge_mac_state = NGE_MAC_STOPPED;
+
+ rw_exit(ngep->rwlock);
+ mutex_exit(ngep->genlock);
+ return (DDI_SUCCESS);
+}
+
/*
* detach(9E) -- Detach a device from the system
*/
@@ -1834,19 +1907,12 @@ nge_detach(dev_info_t *devinfo, ddi_detach_cmd_t cmd)
case DDI_SUSPEND:
/*
* Stop the NIC
- * I suspect that we can actually suspend if the stop
- * routine returns a failure, as the resume will
- * effectively fully reset the hardware (i.e. we don't
- * really save any hardware state). However, nge_m_stop
- * doesn't return an error code.
* Note: This driver doesn't currently support WOL, but
* should it in the future, it is important to
* make sure the PHY remains powered so that the
* wakeup packet can actually be recieved.
*/
- nge_m_stop(ngep);
- ngep->suspended = B_TRUE;
- return (DDI_SUCCESS);
+ return (nge_suspend(ngep));
case DDI_DETACH:
break;