1 /* 2 * Mac80211 power management API for ST-Ericsson CW1200 drivers 3 * 4 * Copyright (c) 2011, ST-Ericsson 5 * Author: Dmitry Tarnyagin <dmitry.tarnyagin@lockless.no> 6 * 7 * This program is free software; you can redistribute it and/or modify 8 * it under the terms of the GNU General Public License version 2 as 9 * published by the Free Software Foundation. 10 */ 11 12 #include <linux/module.h> 13 #include <linux/if_ether.h> 14 #include "cw1200.h" 15 #include "pm.h" 16 #include "sta.h" 17 #include "bh.h" 18 #include "hwbus.h" 19 20 #define CW1200_BEACON_SKIPPING_MULTIPLIER 3 21 22 struct cw1200_udp_port_filter { 23 struct wsm_udp_port_filter_hdr hdr; 24 /* Up to 4 filters are allowed. */ 25 struct wsm_udp_port_filter filters[WSM_MAX_FILTER_ELEMENTS]; 26 } __packed; 27 28 struct cw1200_ether_type_filter { 29 struct wsm_ether_type_filter_hdr hdr; 30 /* Up to 4 filters are allowed. */ 31 struct wsm_ether_type_filter filters[WSM_MAX_FILTER_ELEMENTS]; 32 } __packed; 33 34 static struct cw1200_udp_port_filter cw1200_udp_port_filter_on = { 35 .hdr.num = 2, 36 .filters = { 37 [0] = { 38 .action = WSM_FILTER_ACTION_FILTER_OUT, 39 .type = WSM_FILTER_PORT_TYPE_DST, 40 .port = __cpu_to_le16(67), /* DHCP Bootps */ 41 }, 42 [1] = { 43 .action = WSM_FILTER_ACTION_FILTER_OUT, 44 .type = WSM_FILTER_PORT_TYPE_DST, 45 .port = __cpu_to_le16(68), /* DHCP Bootpc */ 46 }, 47 } 48 }; 49 50 static struct wsm_udp_port_filter_hdr cw1200_udp_port_filter_off = { 51 .num = 0, 52 }; 53 54 #ifndef ETH_P_WAPI 55 #define ETH_P_WAPI 0x88B4 56 #endif 57 58 static struct cw1200_ether_type_filter cw1200_ether_type_filter_on = { 59 .hdr.num = 4, 60 .filters = { 61 [0] = { 62 .action = WSM_FILTER_ACTION_FILTER_IN, 63 .type = __cpu_to_le16(ETH_P_IP), 64 }, 65 [1] = { 66 .action = WSM_FILTER_ACTION_FILTER_IN, 67 .type = __cpu_to_le16(ETH_P_PAE), 68 }, 69 [2] = { 70 .action = WSM_FILTER_ACTION_FILTER_IN, 71 .type = __cpu_to_le16(ETH_P_WAPI), 72 }, 73 [3] = { 74 .action = WSM_FILTER_ACTION_FILTER_IN, 75 .type = __cpu_to_le16(ETH_P_ARP), 76 }, 77 }, 78 }; 79 80 static struct wsm_ether_type_filter_hdr cw1200_ether_type_filter_off = { 81 .num = 0, 82 }; 83 84 /* private */ 85 struct cw1200_suspend_state { 86 unsigned long bss_loss_tmo; 87 unsigned long join_tmo; 88 unsigned long direct_probe; 89 unsigned long link_id_gc; 90 bool beacon_skipping; 91 u8 prev_ps_mode; 92 }; 93 94 static void cw1200_pm_stay_awake_tmo(struct timer_list *unused) 95 { 96 /* XXX what's the point of this ? */ 97 } 98 99 int cw1200_pm_init(struct cw1200_pm_state *pm, 100 struct cw1200_common *priv) 101 { 102 spin_lock_init(&pm->lock); 103 104 timer_setup(&pm->stay_awake, cw1200_pm_stay_awake_tmo, 0); 105 106 return 0; 107 } 108 109 void cw1200_pm_deinit(struct cw1200_pm_state *pm) 110 { 111 del_timer_sync(&pm->stay_awake); 112 } 113 114 void cw1200_pm_stay_awake(struct cw1200_pm_state *pm, 115 unsigned long tmo) 116 { 117 long cur_tmo; 118 spin_lock_bh(&pm->lock); 119 cur_tmo = pm->stay_awake.expires - jiffies; 120 if (!timer_pending(&pm->stay_awake) || cur_tmo < (long)tmo) 121 mod_timer(&pm->stay_awake, jiffies + tmo); 122 spin_unlock_bh(&pm->lock); 123 } 124 125 static long cw1200_suspend_work(struct delayed_work *work) 126 { 127 int ret = cancel_delayed_work(work); 128 long tmo; 129 if (ret > 0) { 130 /* Timer is pending */ 131 tmo = work->timer.expires - jiffies; 132 if (tmo < 0) 133 tmo = 0; 134 } else { 135 tmo = -1; 136 } 137 return tmo; 138 } 139 140 static int cw1200_resume_work(struct cw1200_common *priv, 141 struct delayed_work *work, 142 unsigned long tmo) 143 { 144 if ((long)tmo < 0) 145 return 1; 146 147 return queue_delayed_work(priv->workqueue, work, tmo); 148 } 149 150 int cw1200_can_suspend(struct cw1200_common *priv) 151 { 152 if (atomic_read(&priv->bh_rx)) { 153 wiphy_dbg(priv->hw->wiphy, "Suspend interrupted.\n"); 154 return 0; 155 } 156 return 1; 157 } 158 EXPORT_SYMBOL_GPL(cw1200_can_suspend); 159 160 int cw1200_wow_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan) 161 { 162 struct cw1200_common *priv = hw->priv; 163 struct cw1200_pm_state *pm_state = &priv->pm_state; 164 struct cw1200_suspend_state *state; 165 int ret; 166 167 spin_lock_bh(&pm_state->lock); 168 ret = timer_pending(&pm_state->stay_awake); 169 spin_unlock_bh(&pm_state->lock); 170 if (ret) 171 return -EAGAIN; 172 173 /* Do not suspend when datapath is not idle */ 174 if (priv->tx_queue_stats.num_queued) 175 return -EBUSY; 176 177 /* Make sure there is no configuration requests in progress. */ 178 if (!mutex_trylock(&priv->conf_mutex)) 179 return -EBUSY; 180 181 /* Ensure pending operations are done. 182 * Note also that wow_suspend must return in ~2.5sec, before 183 * watchdog is triggered. 184 */ 185 if (priv->channel_switch_in_progress) 186 goto revert1; 187 188 /* Do not suspend when join is pending */ 189 if (priv->join_pending) 190 goto revert1; 191 192 /* Do not suspend when scanning */ 193 if (down_trylock(&priv->scan.lock)) 194 goto revert1; 195 196 /* Lock TX. */ 197 wsm_lock_tx_async(priv); 198 199 /* Wait to avoid possible race with bh code. 200 * But do not wait too long... 201 */ 202 if (wait_event_timeout(priv->bh_evt_wq, 203 !priv->hw_bufs_used, HZ / 10) <= 0) 204 goto revert2; 205 206 /* Set UDP filter */ 207 wsm_set_udp_port_filter(priv, &cw1200_udp_port_filter_on.hdr); 208 209 /* Set ethernet frame type filter */ 210 wsm_set_ether_type_filter(priv, &cw1200_ether_type_filter_on.hdr); 211 212 /* Allocate state */ 213 state = kzalloc(sizeof(struct cw1200_suspend_state), GFP_KERNEL); 214 if (!state) 215 goto revert3; 216 217 /* Change to legacy PS while going to suspend */ 218 if (!priv->vif->p2p && 219 priv->join_status == CW1200_JOIN_STATUS_STA && 220 priv->powersave_mode.mode != WSM_PSM_PS) { 221 state->prev_ps_mode = priv->powersave_mode.mode; 222 priv->powersave_mode.mode = WSM_PSM_PS; 223 cw1200_set_pm(priv, &priv->powersave_mode); 224 if (wait_event_interruptible_timeout(priv->ps_mode_switch_done, 225 !priv->ps_mode_switch_in_progress, 1*HZ) <= 0) { 226 goto revert4; 227 } 228 } 229 230 /* Store delayed work states. */ 231 state->bss_loss_tmo = 232 cw1200_suspend_work(&priv->bss_loss_work); 233 state->join_tmo = 234 cw1200_suspend_work(&priv->join_timeout); 235 state->direct_probe = 236 cw1200_suspend_work(&priv->scan.probe_work); 237 state->link_id_gc = 238 cw1200_suspend_work(&priv->link_id_gc_work); 239 240 cancel_delayed_work_sync(&priv->clear_recent_scan_work); 241 atomic_set(&priv->recent_scan, 0); 242 243 /* Enable beacon skipping */ 244 if (priv->join_status == CW1200_JOIN_STATUS_STA && 245 priv->join_dtim_period && 246 !priv->has_multicast_subscription) { 247 state->beacon_skipping = true; 248 wsm_set_beacon_wakeup_period(priv, 249 priv->join_dtim_period, 250 CW1200_BEACON_SKIPPING_MULTIPLIER * priv->join_dtim_period); 251 } 252 253 /* Stop serving thread */ 254 if (cw1200_bh_suspend(priv)) 255 goto revert5; 256 257 ret = timer_pending(&priv->mcast_timeout); 258 if (ret) 259 goto revert6; 260 261 /* Store suspend state */ 262 pm_state->suspend_state = state; 263 264 /* Enable IRQ wake */ 265 ret = priv->hwbus_ops->power_mgmt(priv->hwbus_priv, true); 266 if (ret) { 267 wiphy_err(priv->hw->wiphy, 268 "PM request failed: %d. WoW is disabled.\n", ret); 269 cw1200_wow_resume(hw); 270 return -EBUSY; 271 } 272 273 /* Force resume if event is coming from the device. */ 274 if (atomic_read(&priv->bh_rx)) { 275 cw1200_wow_resume(hw); 276 return -EAGAIN; 277 } 278 279 return 0; 280 281 revert6: 282 WARN_ON(cw1200_bh_resume(priv)); 283 revert5: 284 cw1200_resume_work(priv, &priv->bss_loss_work, 285 state->bss_loss_tmo); 286 cw1200_resume_work(priv, &priv->join_timeout, 287 state->join_tmo); 288 cw1200_resume_work(priv, &priv->scan.probe_work, 289 state->direct_probe); 290 cw1200_resume_work(priv, &priv->link_id_gc_work, 291 state->link_id_gc); 292 revert4: 293 kfree(state); 294 revert3: 295 wsm_set_udp_port_filter(priv, &cw1200_udp_port_filter_off); 296 wsm_set_ether_type_filter(priv, &cw1200_ether_type_filter_off); 297 revert2: 298 wsm_unlock_tx(priv); 299 up(&priv->scan.lock); 300 revert1: 301 mutex_unlock(&priv->conf_mutex); 302 return -EBUSY; 303 } 304 305 int cw1200_wow_resume(struct ieee80211_hw *hw) 306 { 307 struct cw1200_common *priv = hw->priv; 308 struct cw1200_pm_state *pm_state = &priv->pm_state; 309 struct cw1200_suspend_state *state; 310 311 state = pm_state->suspend_state; 312 pm_state->suspend_state = NULL; 313 314 /* Disable IRQ wake */ 315 priv->hwbus_ops->power_mgmt(priv->hwbus_priv, false); 316 317 /* Scan.lock must be released before BH is resumed other way 318 * in case when BSS_LOST command arrived the processing of the 319 * command will be delayed. 320 */ 321 up(&priv->scan.lock); 322 323 /* Resume BH thread */ 324 WARN_ON(cw1200_bh_resume(priv)); 325 326 /* Restores previous PS mode */ 327 if (!priv->vif->p2p && priv->join_status == CW1200_JOIN_STATUS_STA) { 328 priv->powersave_mode.mode = state->prev_ps_mode; 329 cw1200_set_pm(priv, &priv->powersave_mode); 330 } 331 332 if (state->beacon_skipping) { 333 wsm_set_beacon_wakeup_period(priv, priv->beacon_int * 334 priv->join_dtim_period > 335 MAX_BEACON_SKIP_TIME_MS ? 1 : 336 priv->join_dtim_period, 0); 337 state->beacon_skipping = false; 338 } 339 340 /* Resume delayed work */ 341 cw1200_resume_work(priv, &priv->bss_loss_work, 342 state->bss_loss_tmo); 343 cw1200_resume_work(priv, &priv->join_timeout, 344 state->join_tmo); 345 cw1200_resume_work(priv, &priv->scan.probe_work, 346 state->direct_probe); 347 cw1200_resume_work(priv, &priv->link_id_gc_work, 348 state->link_id_gc); 349 350 /* Remove UDP port filter */ 351 wsm_set_udp_port_filter(priv, &cw1200_udp_port_filter_off); 352 353 /* Remove ethernet frame type filter */ 354 wsm_set_ether_type_filter(priv, &cw1200_ether_type_filter_off); 355 356 /* Unlock datapath */ 357 wsm_unlock_tx(priv); 358 359 /* Unlock configuration mutex */ 360 mutex_unlock(&priv->conf_mutex); 361 362 /* Free memory */ 363 kfree(state); 364 365 return 0; 366 } 367