1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * Copyright (c) 1996, 2003 VIA Networking Technologies, Inc.
4  * All rights reserved.
5  *
6  * File: power.c
7  *
8  * Purpose: Handles 802.11 power management  functions
9  *
10  * Author: Lyndon Chen
11  *
12  * Date: July 17, 2002
13  *
14  * Functions:
15  *      PSvEnablePowerSaving - Enable Power Saving Mode
16  *      PSvDiasblePowerSaving - Disable Power Saving Mode
17  *      PSbConsiderPowerDown - Decide if we can Power Down
18  *      PSvSendPSPOLL - Send PS-POLL packet
19  *      PSbSendNullPacket - Send Null packet
20  *      PSbIsNextTBTTWakeUp - Decide if we need to wake up at next Beacon
21  *
22  * Revision History:
23  *
24  */
25 
26 #include "mac.h"
27 #include "device.h"
28 #include "power.h"
29 #include "card.h"
30 
31 /*---------------------  Static Definitions -------------------------*/
32 
33 /*---------------------  Static Classes  ----------------------------*/
34 
35 /*---------------------  Static Functions  --------------------------*/
36 
37 /*---------------------  Export Variables  --------------------------*/
38 
39 /*---------------------  Export Functions  --------------------------*/
40 
41 /*
42  *
43  * Routine Description:
44  * Enable hw power saving functions
45  *
46  * Return Value:
47  *    None.
48  *
49  */
50 
51 void
PSvEnablePowerSaving(struct vnt_private * priv,unsigned short wListenInterval)52 PSvEnablePowerSaving(
53 	struct vnt_private *priv,
54 	unsigned short wListenInterval
55 )
56 {
57 	u16 wAID = priv->current_aid | BIT(14) | BIT(15);
58 
59 	/* set period of power up before TBTT */
60 	VNSvOutPortW(priv->PortOffset + MAC_REG_PWBT, C_PWBT);
61 	if (priv->op_mode != NL80211_IFTYPE_ADHOC) {
62 		/* set AID */
63 		VNSvOutPortW(priv->PortOffset + MAC_REG_AIDATIM, wAID);
64 	} else {
65 		/* set ATIM Window */
66 #if 0 /* TODO atim window */
67 		MACvWriteATIMW(priv->PortOffset, pMgmt->wCurrATIMWindow);
68 #endif
69 	}
70 	/* Set AutoSleep */
71 	MACvRegBitsOn(priv->PortOffset, MAC_REG_PSCFG, PSCFG_AUTOSLEEP);
72 	/* Set HWUTSF */
73 	MACvRegBitsOn(priv->PortOffset, MAC_REG_TFTCTL, TFTCTL_HWUTSF);
74 
75 	if (wListenInterval >= 2) {
76 		/* clear always listen beacon */
77 		MACvRegBitsOff(priv->PortOffset, MAC_REG_PSCTL, PSCTL_ALBCN);
78 		/* first time set listen next beacon */
79 		MACvRegBitsOn(priv->PortOffset, MAC_REG_PSCTL, PSCTL_LNBCN);
80 	} else {
81 		/* always listen beacon */
82 		MACvRegBitsOn(priv->PortOffset, MAC_REG_PSCTL, PSCTL_ALBCN);
83 	}
84 
85 	/* enable power saving hw function */
86 	MACvRegBitsOn(priv->PortOffset, MAC_REG_PSCTL, PSCTL_PSEN);
87 	priv->bEnablePSMode = true;
88 
89 	priv->bPWBitOn = true;
90 	pr_debug("PS:Power Saving Mode Enable...\n");
91 }
92 
93 /*
94  *
95  * Routine Description:
96  * Disable hw power saving functions
97  *
98  * Return Value:
99  *    None.
100  *
101  */
102 
103 void
PSvDisablePowerSaving(struct vnt_private * priv)104 PSvDisablePowerSaving(
105 	struct vnt_private *priv
106 )
107 {
108 	/* disable power saving hw function */
109 	MACbPSWakeup(priv);
110 	/* clear AutoSleep */
111 	MACvRegBitsOff(priv->PortOffset, MAC_REG_PSCFG, PSCFG_AUTOSLEEP);
112 	/* clear HWUTSF */
113 	MACvRegBitsOff(priv->PortOffset, MAC_REG_TFTCTL, TFTCTL_HWUTSF);
114 	/* set always listen beacon */
115 	MACvRegBitsOn(priv->PortOffset, MAC_REG_PSCTL, PSCTL_ALBCN);
116 
117 	priv->bEnablePSMode = false;
118 
119 	priv->bPWBitOn = false;
120 }
121 
122 /*
123  *
124  * Routine Description:
125  * Check if Next TBTT must wake up
126  *
127  * Return Value:
128  *    None.
129  *
130  */
131 
132 bool
PSbIsNextTBTTWakeUp(struct vnt_private * priv)133 PSbIsNextTBTTWakeUp(
134 	struct vnt_private *priv
135 )
136 {
137 	struct ieee80211_hw *hw = priv->hw;
138 	struct ieee80211_conf *conf = &hw->conf;
139 	bool wake_up = false;
140 
141 	if (conf->listen_interval > 1) {
142 		if (!priv->wake_up_count)
143 			priv->wake_up_count = conf->listen_interval;
144 
145 		--priv->wake_up_count;
146 
147 		if (priv->wake_up_count == 1) {
148 			/* Turn on wake up to listen next beacon */
149 			MACvRegBitsOn(priv->PortOffset,
150 				      MAC_REG_PSCTL, PSCTL_LNBCN);
151 			wake_up = true;
152 		}
153 	}
154 
155 	return wake_up;
156 }
157