changeset 11101:69561cde8165

6900514 Need to support suspend/resume for CISCO Aironet AIR-PCM352 pcmcia wifi driver(pcan) 6901512 Need to support suspend/resume for Orinoco pcmcia wifi driver(pcwl)
author Qin Michael Li <Mikore.Li@Sun.COM>
date Thu, 19 Nov 2009 11:57:44 +0800
parents 643dac9d4a2c
children b91faef0c984
files usr/src/uts/common/io/pcan/pcan.c usr/src/uts/common/io/pcan/pcan.h usr/src/uts/common/io/pcwl/pcwl.c usr/src/uts/common/io/pcwl/pcwl.h usr/src/uts/common/pcmcia/nexus/pcmcia.c
diffstat 5 files changed, 207 insertions(+), 21 deletions(-) [+]
line wrap: on
line diff
--- a/usr/src/uts/common/io/pcan/pcan.c	Thu Nov 19 11:32:59 2009 +0800
+++ b/usr/src/uts/common/io/pcan/pcan.c	Thu Nov 19 11:57:44 2009 +0800
@@ -40,6 +40,7 @@
 #include <sys/sunddi.h>
 #include <sys/dlpi.h>
 #include <sys/ethernet.h>
+#include <sys/strsubr.h>
 #include <sys/strsun.h>
 #include <sys/stat.h>
 #include <sys/byteorder.h>
@@ -526,8 +527,8 @@
 
 	(void) mac_unregister(pcan_p->pcan_mh);
 
-	mutex_enter(&pcan_p->pcan_glock);
 	if (pcan_p->pcan_device_type == PCAN_DEVICE_PCI) {
+		mutex_enter(&pcan_p->pcan_glock);
 		ddi_remove_intr(dip, 0, pcan_p->pcan_ib_cookie);
 		pcan_free_dma(pcan_p);
 		if (pcan_p->pcan_handle0)
@@ -536,12 +537,12 @@
 			ddi_regs_map_free(&pcan_p->pcan_handle1);
 		if (pcan_p->pcan_handle2)
 			ddi_regs_map_free(&pcan_p->pcan_handle2);
+		mutex_exit(&pcan_p->pcan_glock);
 	} else if (pcan_p->pcan_device_type == PCAN_DEVICE_PCCARD) {
 		pcan_unregister_cs(pcan_p);
 	} else {
 		cmn_err(CE_WARN, "pcan detach: unsupported device type\n");
 	}
-	mutex_exit(&pcan_p->pcan_glock);
 	pcan_destroy_locks(pcan_p);
 	if (pcan_p->pcan_info_softint_id)
 		ddi_remove_softintr(pcan_p->pcan_info_softint_id);
@@ -652,7 +653,6 @@
 
 	if (pcan_p->pcan_flag & PCAN_CARD_READY) {
 		pcan_card_remove(pcan_p);
-		pcan_p->pcan_flag &= ~PCAN_CARD_READY;
 	}
 	mutex_destroy(&pcan_p->pcan_cslock);
 	cv_destroy(&pcan_p->pcan_cscv);
@@ -701,6 +701,9 @@
 		(void) strcpy(ci_p->VendorName, CS_SUN_VENDOR_DESCRIPTION);
 		ci_p->Attributes |= CS_CLIENT_INFO_VALID;
 		break;
+	case CS_EVENT_PM_SUSPEND:
+		pcan_do_suspend(pcan_p);
+		break;
 	default:
 		ret = CS_UNSUPPORTED_EVENT;
 		break;
@@ -721,6 +724,7 @@
 	cistpl_config_t config;
 	cistpl_cftable_entry_t *tbl_p;
 	register client_handle_t chdl = pcan_p->pcan_chdl;
+	modify_config_t cfgmod;
 
 	bzero(&tuple, sizeof (tuple));
 	tuple.DesiredTuple = CISTPL_MANFID;
@@ -845,6 +849,33 @@
 		cmn_err(CE_WARN, "pcan: RequestConfiguration failed %x\n", ret);
 		goto un_irq;
 	}
+
+	if (pcan_p->pcan_flag & PCAN_SUSPENDED) {
+		mutex_enter(&pcan_p->pcan_glock);
+		pcan_reset_backend(pcan_p, pcan_p->pcan_reset_delay);
+		/* turn on CS interrupt */
+		cfgmod.Attributes = CONF_ENABLE_IRQ_STEERING |
+		    CONF_IRQ_CHANGE_VALID;
+		cfgmod.Vpp1 = 50;
+		cfgmod.Vpp2 = 50;
+		(void) csx_ModifyConfiguration(pcan_p->pcan_chdl, &cfgmod);
+
+		if (ret = pcan_init_nicmem(pcan_p)) {
+			cmn_err(CE_WARN, "pcan insert: init_nicmem failed %x\n",
+			    ret);
+		}
+		PCAN_DISABLE_INTR_CLEAR(pcan_p);
+		ret = pcan_set_cmd(pcan_p, AN_CMD_DISABLE, 0);
+		PCANDBG((CE_NOTE, "pcan insert set cmd ret =%x\n", ret));
+		pcan_p->pcan_flag &= ~PCAN_SUSPENDED;
+		mutex_exit(&pcan_p->pcan_glock);
+	}
+
+	if (pcan_p->pcan_flag & PCAN_PLUMBED) {
+		pcan_start(pcan_p);
+		pcan_p->pcan_flag &= ~PCAN_PLUMBED;
+		PCANDBG((CE_NOTE, "pcan insert: active interrupt\n"));
+	}
 	return (CS_SUCCESS);
 un_irq:
 	(void) csx_ReleaseIRQ(chdl, &irq);
@@ -862,6 +893,33 @@
  * assume card is already removed, don't touch the hardware
  */
 static void
+pcan_do_suspend(pcan_maci_t *pcan_p)
+{
+	int ret;
+	if (pcan_p->pcan_flag & PCAN_CARD_LINKUP) {
+		if (pcan_p->pcan_connect_timeout_id != 0) {
+			(void) untimeout(pcan_p->pcan_connect_timeout_id);
+			pcan_p->pcan_connect_timeout_id = 0;
+		}
+		mutex_enter(&pcan_p->pcan_glock);
+		pcan_p->pcan_flag &= ~PCAN_CARD_LINKUP;
+		if (ret = pcan_set_cmd(pcan_p, AN_CMD_DISABLE, 0))
+			PCANDBG((CE_NOTE, "pcan: disable failed, ret %d\n",
+			    ret));
+		if (ret = pcan_loaddef(pcan_p))
+			PCANDBG((CE_NOTE, "pcan: loaddef failed, ret %d\n",
+			    ret));
+		mac_link_update(GLD3(pcan_p), LINK_STATE_DOWN);
+		mutex_exit(&pcan_p->pcan_glock);
+	}
+	pcan_p->pcan_flag |= PCAN_SUSPENDED;
+}
+
+
+/*
+ * assume card is already removed, don't touch the hardware
+ */
+static void
 pcan_card_remove(pcan_maci_t *pcan_p)
 {
 	int ret;
@@ -870,6 +928,23 @@
 
 	if (!(pcan_p->pcan_flag & PCAN_CARD_READY))
 		return;
+	if (pcan_p->pcan_connect_timeout_id != 0) {
+		(void) untimeout(pcan_p->pcan_connect_timeout_id);
+		pcan_p->pcan_connect_timeout_id = 0;
+	}
+
+	if (pcan_p->pcan_flag & PCAN_CARD_LINKUP) {
+		pcan_p->pcan_flag &= ~PCAN_CARD_LINKUP;
+		mac_link_update(GLD3(pcan_p), LINK_STATE_DOWN);
+	}
+	mutex_enter(&pcan_p->pcan_glock);
+	if (pcan_p->pcan_flag & PCAN_CARD_INTREN) {
+		pcan_stop_locked(pcan_p);
+		pcan_p->pcan_flag |= PCAN_PLUMBED;
+	}
+	pcan_p->pcan_flag &= ~PCAN_CARD_READY;
+	mutex_exit(&pcan_p->pcan_glock);
+
 	if (ret = csx_ReleaseConfiguration(pcan_p->pcan_chdl, NULL))
 		cmn_err(CE_WARN, "pcan: ReleaseConfiguration failed %x\n", ret);
 
@@ -878,6 +953,7 @@
 		cmn_err(CE_WARN, "pcan: ReleaseIRQ failed %x\n", ret);
 
 	ddi_remove_softintr(pcan_p->pcan_softint_id);
+	pcan_p->pcan_softint_id  = 0;
 
 	bzero(&io, sizeof (io));
 	io.BasePort1.handle = pcan_p->pcan_port;
@@ -886,7 +962,7 @@
 		cmn_err(CE_WARN, "pcan: Release IO failed %x\n", ret);
 
 	pcan_p->pcan_port = 0;
-	pcan_p->pcan_flag &= ~PCAN_CARD_READY;
+	PCANDBG((CE_NOTE, "pcan: removed\n"));
 }
 
 /*
@@ -973,7 +1049,7 @@
 #ifdef PCAN_SEND_DEBUG
 	struct an_ltv_status radio_status;
 #endif /* PCAN_SEND_DEBUG */
-	uint16_t pkt_len, xmt_id, ring_idx;
+	uint16_t pkt_len, xmt_id, ring_idx, r = 0;
 	struct ieee80211_frame *wh;
 	int i = 0;
 
@@ -1084,7 +1160,7 @@
 	(void) WRCH1(pcan_p, xmt_id, 0, (uint16_t *)buf_p, 0x38); /* frm */
 	(void) WRPKT(pcan_p, xmt_id, 0x38, (uint16_t *)(buf_p + 0x38),
 	    pkt_len + 12);
-	ring_idx = pcan_set_cmd(pcan_p, AN_CMD_TX, xmt_id);
+	r = pcan_set_cmd(pcan_p, AN_CMD_TX, xmt_id);
 	mutex_exit(&pcan_p->pcan_glock);
 
 	PCANDBG((CE_NOTE, "pcan: pkt_len=0x44+%x=%x xmt=%x ret=%x\n",
@@ -1097,7 +1173,7 @@
 		PCANDBG((CE_NOTE, "pcan: radio status:\n"));
 	}
 #endif /* PCAN_SEND_DEBUG */
-	if (ring_idx)
+	if (r)
 		return (PCAN_FAIL);
 	else {
 		freemsg(mblk_p);
@@ -1214,7 +1290,8 @@
 	if ((pcan_p->pcan_flag & (PCAN_CARD_LINKUP | PCAN_CARD_READY)) !=
 	    (PCAN_CARD_LINKUP | PCAN_CARD_READY)) {
 		mutex_exit(&pcan_p->pcan_glock);
-		return (mp);
+		freemsgchain(mp);
+		return (NULL);
 	}
 	mutex_exit(&pcan_p->pcan_glock);
 	while (mp != NULL) {
@@ -2336,7 +2413,6 @@
     struct an_ltv_scanresult *scanresult_p)
 {
 	uint16_t ret, len;
-
 	if (rw != PCAN_READ_LTV) {
 		cmn_err(CE_WARN, "pcan scan_ltv: readonly rid %x\n", type);
 		return (PCAN_FAIL);
@@ -4206,6 +4282,10 @@
 			pcan_p->pcan_connect_timeout_id = 0;
 		}
 		mutex_enter(&pcan_p->pcan_glock);
+		if (!(pcan_p->pcan_flag & PCAN_CARD_READY)) {
+			mutex_exit(&pcan_p->pcan_glock);
+			return (PCAN_FAIL);
+		}
 		ret = pcan_cmd_scan(pcan_p);
 		/*
 		 * a trick here.
@@ -4239,6 +4319,10 @@
 			pcan_p->pcan_connect_timeout_id = 0;
 		}
 		mutex_enter(&pcan_p->pcan_glock);
+		if (!(pcan_p->pcan_flag & PCAN_CARD_READY)) {
+			mutex_exit(&pcan_p->pcan_glock);
+			return (PCAN_FAIL);
+		}
 		pcan_p->pcan_flag &= ~PCAN_CARD_LINKUP;
 		if (ret = pcan_set_cmd(pcan_p, AN_CMD_DISABLE, 0)) {
 			ret = (int)WL_HW_ERROR;
@@ -4258,6 +4342,10 @@
 			pcan_p->pcan_connect_timeout_id = 0;
 		}
 		mutex_enter(&pcan_p->pcan_glock);
+		if (!(pcan_p->pcan_flag & PCAN_CARD_READY)) {
+			mutex_exit(&pcan_p->pcan_glock);
+			return (PCAN_FAIL);
+		}
 		if (ret = pcan_set_cmd(pcan_p, AN_CMD_DISABLE, 0)) {
 			ret = (int)WL_HW_ERROR;
 			break;
@@ -4507,7 +4595,7 @@
 	case MAC_PROP_WL_SETOPTIE:
 	case MAC_PROP_WL_MLME:
 		cmn_err(CE_WARN, "pcan_getprop:"
-		    "opmode not support\n");
+		    "opmode not support %x\n", wldp_pr_num);
 		err = ENOTSUP;
 		break;
 	default:
--- a/usr/src/uts/common/io/pcan/pcan.h	Thu Nov 19 11:32:59 2009 +0800
+++ b/usr/src/uts/common/io/pcan/pcan.h	Thu Nov 19 11:57:44 2009 +0800
@@ -1,5 +1,5 @@
 /*
- * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -39,8 +39,6 @@
 #ifndef _SYS_PCAN_H
 #define	_SYS_PCAN_H
 
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
 #ifdef	__cplusplus
 extern "C" {
 #endif
@@ -1212,6 +1210,8 @@
 #define	PCAN_CARD_SEND		0x20
 #define	PCAN_CARD_READY		0x40
 #define	PCAN_CARD_FAILED	0x80
+#define	PCAN_PLUMBED		0x100
+#define	PCAN_SUSPENDED		0x200
 
 #define	PCAN_STATE_IDLE		0x1
 
@@ -1230,6 +1230,7 @@
 static int	pcan_ev_hdlr(event_t ev, int pri, event_callback_args_t *arg);
 static void	pcan_card_remove(pcan_maci_t *pcan_p);
 static int	pcan_init_nicmem(pcan_maci_t *pcan_p);
+static void	pcan_do_suspend(pcan_maci_t *pcan_p);
 
 /*
  * high level device access primitives, glock must held before calling
--- a/usr/src/uts/common/io/pcwl/pcwl.c	Thu Nov 19 11:32:59 2009 +0800
+++ b/usr/src/uts/common/io/pcwl/pcwl.c	Thu Nov 19 11:57:44 2009 +0800
@@ -40,6 +40,7 @@
 #include <sys/sunddi.h>
 #include <sys/dlpi.h>
 #include <sys/ethernet.h>
+#include <sys/strsubr.h>
 #include <sys/strsun.h>
 #include <sys/stat.h>
 #include <sys/byteorder.h>
@@ -86,6 +87,8 @@
 static int	pcwl_m_getprop(void *arg, const char *pr_name,
     mac_prop_id_t wldp_pr_num, uint_t pr_flags,
     uint_t wldp_length, void *wldp_buf, uint_t *perm);
+static void
+pcwl_delay(pcwl_maci_t *, clock_t);
 
 mac_callbacks_t pcwl_m_callbacks = {
 	MC_IOCTL | MC_SETPROP | MC_GETPROP,
@@ -479,15 +482,15 @@
 	mutex_exit(&pcwl_p->pcwl_scanlist_lock);
 	(void) mac_unregister(pcwl_p->pcwl_mh);
 
-	mutex_enter(&pcwl_p->pcwl_glock);
 	if (pcwl_p->pcwl_device_type == PCWL_DEVICE_PCI) {
+		mutex_enter(&pcwl_p->pcwl_glock);
 		ddi_remove_intr(dip, 0, pcwl_p->pcwl_ib_cookie);
 		ddi_regs_map_free(&pcwl_p->pcwl_handle);
 		ddi_regs_map_free(&pcwl_p->pcwl_cfg_handle);
+		mutex_exit(&pcwl_p->pcwl_glock);
 	} else if (pcwl_p->pcwl_device_type == PCWL_DEVICE_PCCARD) {
 		pcwl_unregister_cs(pcwl_p);
 	}
-	mutex_exit(&pcwl_p->pcwl_glock);
 	pcwl_destroy_locks(pcwl_p);
 	ddi_remove_minor_node(dip, NULL);
 	ddi_soft_state_free(pcwl_soft_state_p, ddi_get_instance(dip));
@@ -607,6 +610,9 @@
 	mutex_destroy(&pcwl_p->pcwl_glock);
 }
 
+static void
+pcwl_do_suspend(pcwl_maci_t *pcwl_p);
+
 static int
 pcwl_ev_hdlr(event_t event, int priority, event_callback_args_t *arg)
 {
@@ -641,6 +647,9 @@
 		(void) strcpy(ci_p->VendorName, CS_SUN_VENDOR_DESCRIPTION);
 		ci_p->Attributes |= CS_CLIENT_INFO_VALID;
 		break;
+	case CS_EVENT_PM_SUSPEND:
+		pcwl_do_suspend(pcwl_p);
+		break;
 	default:
 		ret = CS_UNSUPPORTED_EVENT;
 		break;
@@ -649,6 +658,52 @@
 	return (ret);
 }
 
+/*
+ * assume card is already removed, don't touch the hardware
+ */
+static void
+pcwl_do_suspend(pcwl_maci_t *pcwl_p)
+{
+	int ret;
+
+	if (pcwl_p->pcwl_flag & PCWL_CARD_LINKUP) {
+		if (pcwl_p->pcwl_connect_timeout_id != 0) {
+			(void) untimeout(pcwl_p->pcwl_connect_timeout_id);
+			pcwl_p->pcwl_connect_timeout_id = 0;
+		}
+		mutex_enter(&pcwl_p->pcwl_glock);
+		pcwl_p->pcwl_flag &= ~PCWL_CARD_LINKUP;
+		(void) pcwl_set_cmd(pcwl_p, WL_CMD_DISABLE, 0);
+		/*
+		 * A workaround here: If the card is in ad-hoc mode, the
+		 * following scan will not work correctly, so any
+		 * 'dladm connect-wifi' which need a scan first will not
+		 * succeed. software reset the card here as a workround.
+		 */
+		if ((pcwl_p->pcwl_rf.rf_porttype == WL_BSS_IBSS) &&
+		    (pcwl_p->pcwl_chip_type == PCWL_CHIP_LUCENT)) {
+			(void) pcwl_reset_backend(pcwl_p);
+			(void) pcwl_init_nicmem(pcwl_p);
+			pcwl_start_locked(pcwl_p);
+		}
+		if (ret = pcwl_loaddef_rf(pcwl_p)) {
+			PCWLDBG((CE_WARN, "cfg_loaddef_err %d\n", ret));
+		}
+		if (ret = pcwl_set_cmd(pcwl_p, WL_CMD_ENABLE, 0)) {
+			PCWLDBG((CE_WARN, "set enable cmd err\n"));
+		}
+		pcwl_delay(pcwl_p, 1000000);
+		if (ret = pcwl_set_cmd(pcwl_p, WL_CMD_DISABLE, 0)) {
+			PCWLDBG((CE_WARN, "set disable cmd err\n"));
+		}
+		mac_link_update(GLD3(pcwl_p), LINK_STATE_DOWN);
+		mutex_exit(&pcwl_p->pcwl_glock);
+	}
+	pcwl_p->pcwl_flag |= PCWL_CARD_SUSPEND;
+	PCWLDBG((CE_WARN, "pcwl: do suspend\n"));
+}
+
+
 static int
 pcwl_card_insert(pcwl_maci_t *pcwl_p)
 {
@@ -661,6 +716,7 @@
 	cistpl_config_t config;
 	cistpl_cftable_entry_t *tbl_p;
 	register client_handle_t chdl = pcwl_p->pcwl_chdl;
+	modify_config_t cfgmod;
 
 	bzero(&tuple, sizeof (tuple));
 	tuple.DesiredTuple = CISTPL_MANFID;
@@ -785,6 +841,29 @@
 		cmn_err(CE_WARN, "pcwl: RequestConfiguration failed %x\n", ret);
 		goto un_irq;
 	}
+
+	if (pcwl_p->pcwl_flag & PCWL_CARD_SUSPEND) {
+		mutex_enter(&pcwl_p->pcwl_glock);
+		pcwl_reset_backend(pcwl_p);
+		/* turn on CS interrupt */
+		cfgmod.Attributes = CONF_ENABLE_IRQ_STEERING |
+		    CONF_IRQ_CHANGE_VALID;
+		cfgmod.Vpp1 = 50;
+		cfgmod.Vpp2 = 50;
+		(void) csx_ModifyConfiguration(pcwl_p->pcwl_chdl, &cfgmod);
+
+		(void) pcwl_init_nicmem(pcwl_p);
+		pcwl_chip_type(pcwl_p);
+		(void) pcwl_loaddef_rf(pcwl_p);
+		(void) pcwl_set_cmd(pcwl_p, WL_CMD_DISABLE, 0);
+		pcwl_stop_locked(pcwl_p);	/* leaves interface down */
+		pcwl_p->pcwl_flag &= ~PCWL_CARD_SUSPEND;
+		mutex_exit(&pcwl_p->pcwl_glock);
+	}
+	if (pcwl_p->pcwl_flag & PCWL_CARD_PLUMBED) {
+		pcwl_start(pcwl_p);
+		pcwl_p->pcwl_flag &= ~PCWL_CARD_PLUMBED;
+	}
 	return (CS_SUCCESS);
 un_irq:
 	(void) csx_ReleaseIRQ(chdl, &irq);
@@ -814,6 +893,23 @@
 	 */
 	if (!(pcwl_p->pcwl_flag & PCWL_CARD_READY))
 		return;
+
+	if (pcwl_p->pcwl_connect_timeout_id != 0) {
+		(void) untimeout(pcwl_p->pcwl_connect_timeout_id);
+		pcwl_p->pcwl_connect_timeout_id = 0;
+	}
+
+	if (pcwl_p->pcwl_flag & PCWL_CARD_LINKUP) {
+		pcwl_p->pcwl_flag &= ~PCWL_CARD_LINKUP;
+		mac_link_update(GLD3(pcwl_p), LINK_STATE_DOWN);
+	}
+	mutex_enter(&pcwl_p->pcwl_glock);
+	if (pcwl_p->pcwl_flag & PCWL_CARD_INTREN) {
+		pcwl_stop_locked(pcwl_p);
+		pcwl_p->pcwl_flag |= PCWL_CARD_PLUMBED;
+	}
+	pcwl_p->pcwl_flag &= ~PCWL_CARD_READY;
+	mutex_exit(&pcwl_p->pcwl_glock);
 	if (ret = csx_ReleaseConfiguration(pcwl_p->pcwl_chdl, NULL))
 		cmn_err(CE_WARN, "pcwl: ReleaseConfiguration failed %x\n", ret);
 
@@ -830,7 +926,6 @@
 		cmn_err(CE_WARN, "pcwl: ReleaseIO failed %x\n", ret);
 
 	pcwl_p->pcwl_port = 0;
-	pcwl_p->pcwl_flag &= ~PCWL_CARD_READY;
 }
 
 /*
@@ -1030,7 +1125,8 @@
 	if ((pcwl_p->pcwl_flag & (PCWL_CARD_LINKUP | PCWL_CARD_READY)) !=
 	    (PCWL_CARD_LINKUP | PCWL_CARD_READY)) {
 		mutex_exit(&pcwl_p->pcwl_glock);
-		return (mp);
+		freemsgchain(mp);
+		return (NULL);
 	}
 	mutex_exit(&pcwl_p->pcwl_glock);
 	while (mp != NULL) {
--- a/usr/src/uts/common/io/pcwl/pcwl.h	Thu Nov 19 11:32:59 2009 +0800
+++ b/usr/src/uts/common/io/pcwl/pcwl.h	Thu Nov 19 11:57:44 2009 +0800
@@ -1,5 +1,5 @@
 /*
- * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -43,8 +43,6 @@
 #ifndef _SYS_PCWL_H
 #define	_SYS_PCWL_H
 
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
 #ifdef	__cplusplus
 extern "C" {
 #endif
@@ -762,6 +760,8 @@
 #define	PCWL_CARD_READY		0x80
 #define	PCWL_CARD_FAILED	0x100
 #define	PCWL_CARD_INTR		0x200
+#define	PCWL_CARD_PLUMBED	0x400
+#define	PCWL_CARD_SUSPEND	0x800
 
 #define	PCWL_STATE_IDLE		0x1
 
--- a/usr/src/uts/common/pcmcia/nexus/pcmcia.c	Thu Nov 19 11:32:59 2009 +0800
+++ b/usr/src/uts/common/pcmcia/nexus/pcmcia.c	Thu Nov 19 11:57:44 2009 +0800
@@ -3738,7 +3738,8 @@
 	newsock = *socket;
 	/* note: we force CS to always get insert/removal events */
 	sockp->ls_cs_events = pcm_mapevents(newsock.SCIntMask) |
-	    PCE_E2M(PCE_CARD_INSERT) | PCE_E2M(PCE_CARD_REMOVAL);
+	    PCE_E2M(PCE_CARD_INSERT) | PCE_E2M(PCE_CARD_REMOVAL) |
+	    PCE_E2M(PCE_PM_SUSPEND);
 #if defined(PCMCIA_DEBUG)
 	if (pcmcia_debug > 1)
 		cmn_err(CE_CONT,