1 | /* |
2 | * Copyright (c) 2014 Redpine Signals Inc. |
3 | * |
4 | * Permission to use, copy, modify, and/or distribute this software for any |
5 | * purpose with or without fee is hereby granted, provided that the above |
6 | * copyright notice and this permission notice appear in all copies. |
7 | * |
8 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
9 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
10 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR |
11 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
12 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN |
13 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF |
14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
15 | */ |
16 | |
17 | #include <linux/etherdevice.h> |
18 | #include <linux/if.h> |
19 | #include "rsi_debugfs.h" |
20 | #include "rsi_mgmt.h" |
21 | #include "rsi_common.h" |
22 | #include "rsi_ps.h" |
23 | |
24 | char *str_psstate(enum ps_state state) |
25 | { |
26 | switch (state) { |
27 | case PS_NONE: |
28 | return "PS_NONE" ; |
29 | case PS_DISABLE_REQ_SENT: |
30 | return "PS_DISABLE_REQ_SENT" ; |
31 | case PS_ENABLE_REQ_SENT: |
32 | return "PS_ENABLE_REQ_SENT" ; |
33 | case PS_ENABLED: |
34 | return "PS_ENABLED" ; |
35 | default: |
36 | return "INVALID_STATE" ; |
37 | } |
38 | } |
39 | |
40 | static inline void rsi_modify_ps_state(struct rsi_hw *adapter, |
41 | enum ps_state nstate) |
42 | { |
43 | rsi_dbg(INFO_ZONE, fmt: "PS state changed %s => %s\n" , |
44 | str_psstate(state: adapter->ps_state), |
45 | str_psstate(state: nstate)); |
46 | |
47 | adapter->ps_state = nstate; |
48 | } |
49 | |
50 | void rsi_default_ps_params(struct rsi_hw *adapter) |
51 | { |
52 | struct rsi_ps_info *ps_info = &adapter->ps_info; |
53 | |
54 | ps_info->enabled = true; |
55 | ps_info->sleep_type = RSI_SLEEP_TYPE_LP; |
56 | ps_info->tx_threshold = 0; |
57 | ps_info->rx_threshold = 0; |
58 | ps_info->tx_hysterisis = 0; |
59 | ps_info->rx_hysterisis = 0; |
60 | ps_info->monitor_interval = 0; |
61 | ps_info->listen_interval = RSI_DEF_LISTEN_INTERVAL; |
62 | ps_info->num_bcns_per_lis_int = 0; |
63 | ps_info->dtim_interval_duration = 0; |
64 | ps_info->num_dtims_per_sleep = 0; |
65 | ps_info->deep_sleep_wakeup_period = RSI_DEF_DS_WAKEUP_PERIOD; |
66 | } |
67 | |
68 | void rsi_enable_ps(struct rsi_hw *adapter, struct ieee80211_vif *vif) |
69 | { |
70 | if (adapter->ps_state != PS_NONE) { |
71 | rsi_dbg(ERR_ZONE, |
72 | fmt: "%s: Cannot accept enable PS in %s state\n" , |
73 | __func__, str_psstate(state: adapter->ps_state)); |
74 | return; |
75 | } |
76 | |
77 | if (rsi_send_ps_request(adapter, enable: true, vif)) { |
78 | rsi_dbg(ERR_ZONE, |
79 | fmt: "%s: Failed to send PS request to device\n" , |
80 | __func__); |
81 | return; |
82 | } |
83 | |
84 | rsi_modify_ps_state(adapter, nstate: PS_ENABLE_REQ_SENT); |
85 | } |
86 | |
87 | /* This function is used to disable power save */ |
88 | void rsi_disable_ps(struct rsi_hw *adapter, struct ieee80211_vif *vif) |
89 | { |
90 | if (adapter->ps_state != PS_ENABLED) { |
91 | rsi_dbg(ERR_ZONE, |
92 | fmt: "%s: Cannot accept disable PS in %s state\n" , |
93 | __func__, str_psstate(state: adapter->ps_state)); |
94 | return; |
95 | } |
96 | |
97 | if (rsi_send_ps_request(adapter, enable: false, vif)) { |
98 | rsi_dbg(ERR_ZONE, |
99 | fmt: "%s: Failed to send PS request to device\n" , |
100 | __func__); |
101 | return; |
102 | } |
103 | |
104 | rsi_modify_ps_state(adapter, nstate: PS_DISABLE_REQ_SENT); |
105 | } |
106 | |
107 | void rsi_conf_uapsd(struct rsi_hw *adapter, struct ieee80211_vif *vif) |
108 | { |
109 | int ret; |
110 | |
111 | if (adapter->ps_state != PS_ENABLED) |
112 | return; |
113 | |
114 | ret = rsi_send_ps_request(adapter, enable: false, vif); |
115 | if (!ret) |
116 | ret = rsi_send_ps_request(adapter, enable: true, vif); |
117 | if (ret) |
118 | rsi_dbg(ERR_ZONE, |
119 | fmt: "%s: Failed to send PS request to device\n" , |
120 | __func__); |
121 | } |
122 | |
123 | int rsi_handle_ps_confirm(struct rsi_hw *adapter, u8 *msg) |
124 | { |
125 | u16 cfm_type = get_unaligned_le16(p: msg + PS_CONFIRM_INDEX); |
126 | |
127 | switch (cfm_type) { |
128 | case RSI_SLEEP_REQUEST: |
129 | if (adapter->ps_state == PS_ENABLE_REQ_SENT) |
130 | rsi_modify_ps_state(adapter, nstate: PS_ENABLED); |
131 | break; |
132 | case RSI_WAKEUP_REQUEST: |
133 | if (adapter->ps_state == PS_DISABLE_REQ_SENT) |
134 | rsi_modify_ps_state(adapter, nstate: PS_NONE); |
135 | break; |
136 | default: |
137 | rsi_dbg(ERR_ZONE, |
138 | fmt: "Invalid PS confirm type %x in state %s\n" , |
139 | cfm_type, str_psstate(state: adapter->ps_state)); |
140 | return -1; |
141 | } |
142 | |
143 | return 0; |
144 | } |
145 | |
146 | |