xref: /openbmc/linux/drivers/staging/vt6656/power.c (revision ca79522c)
1 /*
2  * Copyright (c) 1996, 2003 VIA Networking Technologies, Inc.
3  * All rights reserved.
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License along
16  * with this program; if not, write to the Free Software Foundation, Inc.,
17  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18  *
19  *
20  * File: power.c
21  *
22  * Purpose: Handles 802.11 power management functions
23  *
24  * Author: Lyndon Chen
25  *
26  * Date: July 17, 2002
27  *
28  * Functions:
29  *      PSvEnablePowerSaving - Enable Power Saving Mode
30  *      PSvDiasblePowerSaving - Disable Power Saving Mode
31  *      PSbConsiderPowerDown - Decide if we can Power Down
32  *      PSvSendPSPOLL - Send PS-POLL packet
33  *      PSbSendNullPacket - Send Null packet
34  *      PSbIsNextTBTTWakeUp - Decide if we need to wake up at next Beacon
35  *
36  * Revision History:
37  *
38  */
39 
40 #include "mac.h"
41 #include "device.h"
42 #include "wmgr.h"
43 #include "power.h"
44 #include "wcmd.h"
45 #include "rxtx.h"
46 #include "card.h"
47 #include "control.h"
48 #include "rndis.h"
49 
50 static int msglevel = MSG_LEVEL_INFO;
51 
52 /*
53  *
54  * Routine Description:
55  * Enable hw power saving functions
56  *
57  * Return Value:
58  *    None.
59  *
60  */
61 
62 void PSvEnablePowerSaving(struct vnt_private *pDevice, u16 wListenInterval)
63 {
64 	struct vnt_manager *pMgmt = &pDevice->vnt_mgmt;
65 	u16 wAID = pMgmt->wCurrAID | BIT14 | BIT15;
66 
67 	/* set period of power up before TBTT */
68 	MACvWriteWord(pDevice, MAC_REG_PWBT, C_PWBT);
69 
70 	if (pDevice->eOPMode != OP_MODE_ADHOC) {
71 		/* set AID */
72 		MACvWriteWord(pDevice, MAC_REG_AIDATIM, wAID);
73 	} else {
74 		/* set ATIM Window */
75 		/* MACvWriteATIMW(pDevice->PortOffset, pMgmt->wCurrATIMWindow); */
76 	}
77 
78 	/* Warren:06-18-2004,the sequence must follow PSEN->AUTOSLEEP->GO2DOZE */
79 	/* enable power saving hw function */
80 	MACvRegBitsOn(pDevice, MAC_REG_PSCTL, PSCTL_PSEN);
81 
82 	/* Set AutoSleep */
83 	MACvRegBitsOn(pDevice, MAC_REG_PSCFG, PSCFG_AUTOSLEEP);
84 
85 	/* Warren:MUST turn on this once before turn on AUTOSLEEP ,or the AUTOSLEEP doesn't work */
86 	MACvRegBitsOn(pDevice, MAC_REG_PSCTL, PSCTL_GO2DOZE);
87 
88 	if (wListenInterval >= 2) {
89 
90 		/* clear always listen beacon */
91 		MACvRegBitsOff(pDevice, MAC_REG_PSCTL, PSCTL_ALBCN);
92 
93 		/* first time set listen next beacon */
94 		MACvRegBitsOn(pDevice, MAC_REG_PSCTL, PSCTL_LNBCN);
95 
96 		pMgmt->wCountToWakeUp = wListenInterval;
97 
98 	} else {
99 
100 		/* always listen beacon */
101 		MACvRegBitsOn(pDevice, MAC_REG_PSCTL, PSCTL_ALBCN);
102 
103 		pMgmt->wCountToWakeUp = 0;
104 	}
105 
106 	pDevice->bEnablePSMode = true;
107 
108 	/* We don't send null pkt in ad hoc mode since beacon will handle this. */
109 	if (pDevice->eOPMode == OP_MODE_INFRASTRUCTURE)
110 		PSbSendNullPacket(pDevice);
111 
112 	pDevice->bPWBitOn = true;
113 	DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "PS:Power Saving Mode Enable...\n");
114 }
115 
116 /*
117  *
118  * Routine Description:
119  * Disable hw power saving functions
120  *
121  * Return Value:
122  *    None.
123  *
124  */
125 
126 void PSvDisablePowerSaving(struct vnt_private *pDevice)
127 {
128 
129 	/* disable power saving hw function */
130 	CONTROLnsRequestOut(pDevice, MESSAGE_TYPE_DISABLE_PS, 0,
131 						0, 0, NULL);
132 
133 	/* clear AutoSleep */
134 	MACvRegBitsOff(pDevice, MAC_REG_PSCFG, PSCFG_AUTOSLEEP);
135 
136 	/* set always listen beacon */
137 	MACvRegBitsOn(pDevice, MAC_REG_PSCTL, PSCTL_ALBCN);
138 	pDevice->bEnablePSMode = false;
139 
140 	if (pDevice->eOPMode == OP_MODE_INFRASTRUCTURE)
141 		PSbSendNullPacket(pDevice);
142 
143 	pDevice->bPWBitOn = false;
144 }
145 
146 /*
147  *
148  * Routine Description:
149  * Consider to power down when no more packets to tx or rx.
150  *
151  * Return Value:
152  *    true, if power down success
153  *    false, if fail
154  */
155 
156 int PSbConsiderPowerDown(struct vnt_private *pDevice, int bCheckRxDMA,
157 	int bCheckCountToWakeUp)
158 {
159 	struct vnt_manager *pMgmt = &pDevice->vnt_mgmt;
160 	u8 byData;
161 
162 	/* check if already in Doze mode */
163 	ControlvReadByte(pDevice, MESSAGE_REQUEST_MACREG,
164 					MAC_REG_PSCTL, &byData);
165 
166 	if ((byData & PSCTL_PS) != 0)
167 		return true;
168 
169 	if (pMgmt->eCurrMode != WMAC_MODE_IBSS_STA) {
170 		/* check if in TIM wake period */
171 		if (pMgmt->bInTIMWake)
172 			return false;
173 	}
174 
175 	/* check scan state */
176 	if (pDevice->bCmdRunning)
177 		return false;
178 
179 	/* Tx Burst */
180 	if (pDevice->bPSModeTxBurst)
181 		return false;
182 
183 	/* Froce PSEN on */
184 	MACvRegBitsOn(pDevice, MAC_REG_PSCTL, PSCTL_PSEN);
185 
186 	if (pMgmt->eCurrMode != WMAC_MODE_IBSS_STA) {
187 		if (bCheckCountToWakeUp && (pMgmt->wCountToWakeUp == 0
188 			|| pMgmt->wCountToWakeUp == 1)) {
189 				return false;
190 		}
191 	}
192 
193 	pDevice->bPSRxBeacon = true;
194 
195 	/* no Tx, no Rx isr, now go to Doze */
196 	MACvRegBitsOn(pDevice, MAC_REG_PSCTL, PSCTL_GO2DOZE);
197 	DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Go to Doze ZZZZZZZZZZZZZZZ\n");
198 	return true;
199 }
200 
201 /*
202  *
203  * Routine Description:
204  * Send PS-POLL packet
205  *
206  * Return Value:
207  *    None.
208  *
209  */
210 
211 void PSvSendPSPOLL(struct vnt_private *pDevice)
212 {
213 	struct vnt_manager *pMgmt = &pDevice->vnt_mgmt;
214 	struct vnt_tx_mgmt *pTxPacket = NULL;
215 
216 	memset(pMgmt->pbyPSPacketPool, 0, sizeof(struct vnt_tx_mgmt)
217 		+ WLAN_HDR_ADDR2_LEN);
218 	pTxPacket = (struct vnt_tx_mgmt *)pMgmt->pbyPSPacketPool;
219 	pTxPacket->p80211Header = (PUWLAN_80211HDR)((u8 *)pTxPacket
220 		+ sizeof(struct vnt_tx_mgmt));
221 
222 	pTxPacket->p80211Header->sA2.wFrameCtl = cpu_to_le16(
223 		(
224 			WLAN_SET_FC_FTYPE(WLAN_TYPE_CTL) |
225 			WLAN_SET_FC_FSTYPE(WLAN_FSTYPE_PSPOLL) |
226 			WLAN_SET_FC_PWRMGT(0)
227 		));
228 
229 	pTxPacket->p80211Header->sA2.wDurationID = pMgmt->wCurrAID | BIT14 | BIT15;
230 	memcpy(pTxPacket->p80211Header->sA2.abyAddr1, pMgmt->abyCurrBSSID, WLAN_ADDR_LEN);
231 	memcpy(pTxPacket->p80211Header->sA2.abyAddr2, pMgmt->abyMACAddr, WLAN_ADDR_LEN);
232 	pTxPacket->cbMPDULen = WLAN_HDR_ADDR2_LEN;
233 	pTxPacket->cbPayloadLen = 0;
234 
235 	/* log failure if sending failed */
236 	if (csMgmt_xmit(pDevice, pTxPacket) != CMD_STATUS_PENDING) {
237 		DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Send PS-Poll packet failed..\n");
238 	}
239 }
240 
241 /*
242  *
243  * Routine Description:
244  * Send NULL packet to AP for notification power state of STA
245  *
246  * Return Value:
247  *    None.
248  *
249  */
250 
251 int PSbSendNullPacket(struct vnt_private *pDevice)
252 {
253 	struct vnt_tx_mgmt *pTxPacket = NULL;
254 	struct vnt_manager *pMgmt = &pDevice->vnt_mgmt;
255 	u16 flags = 0;
256 
257 	if (pDevice->bLinkPass == false)
258 		return false;
259 
260 	if ((pDevice->bEnablePSMode == false) &&
261 		(pDevice->fTxDataInSleep == false)) {
262 			return false;
263 	}
264 
265 	memset(pMgmt->pbyPSPacketPool, 0, sizeof(struct vnt_tx_mgmt)
266 		+ WLAN_NULLDATA_FR_MAXLEN);
267 	pTxPacket = (struct vnt_tx_mgmt *)pMgmt->pbyPSPacketPool;
268 	pTxPacket->p80211Header = (PUWLAN_80211HDR)((u8 *)pTxPacket
269 		+ sizeof(struct vnt_tx_mgmt));
270 
271 	flags = WLAN_SET_FC_FTYPE(WLAN_TYPE_DATA) |
272                         WLAN_SET_FC_FSTYPE(WLAN_FSTYPE_NULL);
273 
274 	if (pDevice->bEnablePSMode)
275 		flags |= WLAN_SET_FC_PWRMGT(1);
276 	else
277 		flags |= WLAN_SET_FC_PWRMGT(0);
278 
279 	pTxPacket->p80211Header->sA3.wFrameCtl = cpu_to_le16(flags);
280 
281 	if (pMgmt->eCurrMode != WMAC_MODE_IBSS_STA)
282 		pTxPacket->p80211Header->sA3.wFrameCtl |= cpu_to_le16((u16)WLAN_SET_FC_TODS(1));
283 
284 	memcpy(pTxPacket->p80211Header->sA3.abyAddr1, pMgmt->abyCurrBSSID, WLAN_ADDR_LEN);
285 	memcpy(pTxPacket->p80211Header->sA3.abyAddr2, pMgmt->abyMACAddr, WLAN_ADDR_LEN);
286 	memcpy(pTxPacket->p80211Header->sA3.abyAddr3, pMgmt->abyCurrBSSID, WLAN_BSSID_LEN);
287 	pTxPacket->cbMPDULen = WLAN_HDR_ADDR3_LEN;
288 	pTxPacket->cbPayloadLen = 0;
289 	/* log error if sending failed */
290 	if (csMgmt_xmit(pDevice, pTxPacket) != CMD_STATUS_PENDING) {
291 		DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Send Null Packet failed !\n");
292 		return false;
293 	}
294 	return true;
295 }
296 
297 /*
298  *
299  * Routine Description:
300  * Check if Next TBTT must wake up
301  *
302  * Return Value:
303  *    None.
304  *
305  */
306 
307 int PSbIsNextTBTTWakeUp(struct vnt_private *pDevice)
308 {
309 	struct vnt_manager *pMgmt = &pDevice->vnt_mgmt;
310 	int bWakeUp = false;
311 
312 	if (pMgmt->wListenInterval >= 2) {
313 		if (pMgmt->wCountToWakeUp == 0)
314 			pMgmt->wCountToWakeUp = pMgmt->wListenInterval;
315 
316 		pMgmt->wCountToWakeUp--;
317 
318 		if (pMgmt->wCountToWakeUp == 1) {
319 			/* Turn on wake up to listen next beacon */
320 			MACvRegBitsOn(pDevice, MAC_REG_PSCTL, PSCTL_LNBCN);
321 			pDevice->bPSRxBeacon = false;
322 			bWakeUp = true;
323 		} else if (!pDevice->bPSRxBeacon) {
324 			/* Listen until RxBeacon */
325 			MACvRegBitsOn(pDevice, MAC_REG_PSCTL, PSCTL_LNBCN);
326 		}
327 	}
328 	return bWakeUp;
329 }
330 
331