Mercurial > illumos > illumos-gate
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,