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(unsigned long arg) 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 setup_timer(&pm->stay_awake, cw1200_pm_stay_awake_tmo, 105 (unsigned long)pm); 106 107 return 0; 108 } 109 110 void cw1200_pm_deinit(struct cw1200_pm_state *pm) 111 { 112 del_timer_sync(&pm->stay_awake); 113 } 114 115 void cw1200_pm_stay_awake(struct cw1200_pm_state *pm, 116 unsigned long tmo) 117 { 118 long cur_tmo; 119 spin_lock_bh(&pm->lock); 120 cur_tmo = pm->stay_awake.expires - jiffies; 121 if (!timer_pending(&pm->stay_awake) || cur_tmo < (long)tmo) 122 mod_timer(&pm->stay_awake, jiffies + tmo); 123 spin_unlock_bh(&pm->lock); 124 } 125 126 static long cw1200_suspend_work(struct delayed_work *work) 127 { 128 int ret = cancel_delayed_work(work); 129 long tmo; 130 if (ret > 0) { 131 /* Timer is pending */ 132 tmo = work->timer.expires - jiffies; 133 if (tmo < 0) 134 tmo = 0; 135 } else { 136 tmo = -1; 137 } 138 return tmo; 139 } 140 141 static int cw1200_resume_work(struct cw1200_common *priv, 142 struct delayed_work *work, 143 unsigned long tmo) 144 { 145 if ((long)tmo < 0) 146 return 1; 147 148 return queue_delayed_work(priv->workqueue, work, tmo); 149 } 150 151 int cw1200_can_suspend(struct cw1200_common *priv) 152 { 153 if (atomic_read(&priv->bh_rx)) { 154 wiphy_dbg(priv->hw->wiphy, "Suspend interrupted.\n"); 155 return 0; 156 } 157 return 1; 158 } 159 EXPORT_SYMBOL_GPL(cw1200_can_suspend); 160 161 int cw1200_wow_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan) 162 { 163 struct cw1200_common *priv = hw->priv; 164 struct cw1200_pm_state *pm_state = &priv->pm_state; 165 struct cw1200_suspend_state *state; 166 int ret; 167 168 spin_lock_bh(&pm_state->lock); 169 ret = timer_pending(&pm_state->stay_awake); 170 spin_unlock_bh(&pm_state->lock); 171 if (ret) 172 return -EAGAIN; 173 174 /* Do not suspend when datapath is not idle */ 175 if (priv->tx_queue_stats.num_queued) 176 return -EBUSY; 177 178 /* Make sure there is no configuration requests in progress. */ 179 if (!mutex_trylock(&priv->conf_mutex)) 180 return -EBUSY; 181 182 /* Ensure pending operations are done. 183 * Note also that wow_suspend must return in ~2.5sec, before 184 * watchdog is triggered. 185 */ 186 if (priv->channel_switch_in_progress) 187 goto revert1; 188 189 /* Do not suspend when join is pending */ 190 if (priv->join_pending) 191 goto revert1; 192 193 /* Do not suspend when scanning */ 194 if (down_trylock(&priv->scan.lock)) 195 goto revert1; 196 197 /* Lock TX. */ 198 wsm_lock_tx_async(priv); 199 200 /* Wait to avoid possible race with bh code. 201 * But do not wait too long... 202 */ 203 if (wait_event_timeout(priv->bh_evt_wq, 204 !priv->hw_bufs_used, HZ / 10) <= 0) 205 goto revert2; 206 207 /* Set UDP filter */ 208 wsm_set_udp_port_filter(priv, &cw1200_udp_port_filter_on.hdr); 209 210 /* Set ethernet frame type filter */ 211 wsm_set_ether_type_filter(priv, &cw1200_ether_type_filter_on.hdr); 212 213 /* Allocate state */ 214 state = kzalloc(sizeof(struct cw1200_suspend_state), GFP_KERNEL); 215 if (!state) 216 goto revert3; 217 218 /* Change to legacy PS while going to suspend */ 219 if (!priv->vif->p2p && 220 priv->join_status == CW1200_JOIN_STATUS_STA && 221 priv->powersave_mode.mode != WSM_PSM_PS) { 222 state->prev_ps_mode = priv->powersave_mode.mode; 223 priv->powersave_mode.mode = WSM_PSM_PS; 224 cw1200_set_pm(priv, &priv->powersave_mode); 225 if (wait_event_interruptible_timeout(priv->ps_mode_switch_done, 226 !priv->ps_mode_switch_in_progress, 1*HZ) <= 0) { 227 goto revert4; 228 } 229 } 230 231 /* Store delayed work states. */ 232 state->bss_loss_tmo = 233 cw1200_suspend_work(&priv->bss_loss_work); 234 state->join_tmo = 235 cw1200_suspend_work(&priv->join_timeout); 236 state->direct_probe = 237 cw1200_suspend_work(&priv->scan.probe_work); 238 state->link_id_gc = 239 cw1200_suspend_work(&priv->link_id_gc_work); 240 241 cancel_delayed_work_sync(&priv->clear_recent_scan_work); 242 atomic_set(&priv->recent_scan, 0); 243 244 /* Enable beacon skipping */ 245 if (priv->join_status == CW1200_JOIN_STATUS_STA && 246 priv->join_dtim_period && 247 !priv->has_multicast_subscription) { 248 state->beacon_skipping = true; 249 wsm_set_beacon_wakeup_period(priv, 250 priv->join_dtim_period, 251 CW1200_BEACON_SKIPPING_MULTIPLIER * priv->join_dtim_period); 252 } 253 254 /* Stop serving thread */ 255 if (cw1200_bh_suspend(priv)) 256 goto revert5; 257 258 ret = timer_pending(&priv->mcast_timeout); 259 if (ret) 260 goto revert6; 261 262 /* Store suspend state */ 263 pm_state->suspend_state = state; 264 265 /* Enable IRQ wake */ 266 ret = priv->hwbus_ops->power_mgmt(priv->hwbus_priv, true); 267 if (ret) { 268 wiphy_err(priv->hw->wiphy, 269 "PM request failed: %d. WoW is disabled.\n", ret); 270 cw1200_wow_resume(hw); 271 return -EBUSY; 272 } 273 274 /* Force resume if event is coming from the device. */ 275 if (atomic_read(&priv->bh_rx)) { 276 cw1200_wow_resume(hw); 277 return -EAGAIN; 278 } 279 280 return 0; 281 282 revert6: 283 WARN_ON(cw1200_bh_resume(priv)); 284 revert5: 285 cw1200_resume_work(priv, &priv->bss_loss_work, 286 state->bss_loss_tmo); 287 cw1200_resume_work(priv, &priv->join_timeout, 288 state->join_tmo); 289 cw1200_resume_work(priv, &priv->scan.probe_work, 290 state->direct_probe); 291 cw1200_resume_work(priv, &priv->link_id_gc_work, 292 state->link_id_gc); 293 revert4: 294 kfree(state); 295 revert3: 296 wsm_set_udp_port_filter(priv, &cw1200_udp_port_filter_off); 297 wsm_set_ether_type_filter(priv, &cw1200_ether_type_filter_off); 298 revert2: 299 wsm_unlock_tx(priv); 300 up(&priv->scan.lock); 301 revert1: 302 mutex_unlock(&priv->conf_mutex); 303 return -EBUSY; 304 } 305 306 int cw1200_wow_resume(struct ieee80211_hw *hw) 307 { 308 struct cw1200_common *priv = hw->priv; 309 struct cw1200_pm_state *pm_state = &priv->pm_state; 310 struct cw1200_suspend_state *state; 311 312 state = pm_state->suspend_state; 313 pm_state->suspend_state = NULL; 314 315 /* Disable IRQ wake */ 316 priv->hwbus_ops->power_mgmt(priv->hwbus_priv, false); 317 318 /* Scan.lock must be released before BH is resumed other way 319 * in case when BSS_LOST command arrived the processing of the 320 * command will be delayed. 321 */ 322 up(&priv->scan.lock); 323 324 /* Resume BH thread */ 325 WARN_ON(cw1200_bh_resume(priv)); 326 327 /* Restores previous PS mode */ 328 if (!priv->vif->p2p && priv->join_status == CW1200_JOIN_STATUS_STA) { 329 priv->powersave_mode.mode = state->prev_ps_mode; 330 cw1200_set_pm(priv, &priv->powersave_mode); 331 } 332 333 if (state->beacon_skipping) { 334 wsm_set_beacon_wakeup_period(priv, priv->beacon_int * 335 priv->join_dtim_period > 336 MAX_BEACON_SKIP_TIME_MS ? 1 : 337 priv->join_dtim_period, 0); 338 state->beacon_skipping = false; 339 } 340 341 /* Resume delayed work */ 342 cw1200_resume_work(priv, &priv->bss_loss_work, 343 state->bss_loss_tmo); 344 cw1200_resume_work(priv, &priv->join_timeout, 345 state->join_tmo); 346 cw1200_resume_work(priv, &priv->scan.probe_work, 347 state->direct_probe); 348 cw1200_resume_work(priv, &priv->link_id_gc_work, 349 state->link_id_gc); 350 351 /* Remove UDP port filter */ 352 wsm_set_udp_port_filter(priv, &cw1200_udp_port_filter_off); 353 354 /* Remove ethernet frame type filter */ 355 wsm_set_ether_type_filter(priv, &cw1200_ether_type_filter_off); 356 357 /* Unlock datapath */ 358 wsm_unlock_tx(priv); 359 360 /* Unlock configuration mutex */ 361 mutex_unlock(&priv->conf_mutex); 362 363 /* Free memory */ 364 kfree(state); 365 366 return 0; 367 } 368