.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
---|
1 | 2 | /* |
---|
2 | 3 | * This file is part of wlcore |
---|
3 | 4 | * |
---|
4 | 5 | * Copyright (C) 2008-2010 Nokia Corporation |
---|
5 | 6 | * Copyright (C) 2011-2013 Texas Instruments Inc. |
---|
6 | | - * |
---|
7 | | - * This program is free software; you can redistribute it and/or |
---|
8 | | - * modify it under the terms of the GNU General Public License |
---|
9 | | - * version 2 as published by the Free Software Foundation. |
---|
10 | | - * |
---|
11 | | - * This program is distributed in the hope that it will be useful, but |
---|
12 | | - * WITHOUT ANY WARRANTY; without even the implied warranty of |
---|
13 | | - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
---|
14 | | - * General Public License for more details. |
---|
15 | | - * |
---|
16 | | - * You should have received a copy of the GNU General Public License |
---|
17 | | - * along with this program; if not, write to the Free Software |
---|
18 | | - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA |
---|
19 | | - * 02110-1301 USA |
---|
20 | | - * |
---|
21 | 7 | */ |
---|
22 | 8 | |
---|
23 | 9 | #include <linux/module.h> |
---|
.. | .. |
---|
27 | 13 | #include <linux/interrupt.h> |
---|
28 | 14 | #include <linux/irq.h> |
---|
29 | 15 | #include <linux/pm_runtime.h> |
---|
| 16 | +#include <linux/pm_wakeirq.h> |
---|
30 | 17 | |
---|
31 | 18 | #include "wlcore.h" |
---|
32 | 19 | #include "debug.h" |
---|
.. | .. |
---|
43 | 30 | #include "sysfs.h" |
---|
44 | 31 | |
---|
45 | 32 | #define WL1271_BOOT_RETRIES 3 |
---|
46 | | -#define WL1271_SUSPEND_SLEEP 100 |
---|
47 | 33 | #define WL1271_WAKEUP_TIMEOUT 500 |
---|
48 | 34 | |
---|
49 | 35 | static char *fwlog_param; |
---|
.. | .. |
---|
496 | 482 | } |
---|
497 | 483 | |
---|
498 | 484 | /* update the host-chipset time offset */ |
---|
499 | | - wl->time_offset = (ktime_get_boot_ns() >> 10) - |
---|
| 485 | + wl->time_offset = (ktime_get_boottime_ns() >> 10) - |
---|
500 | 486 | (s64)(status->fw_localtime); |
---|
501 | 487 | |
---|
502 | 488 | wl->fw_fast_lnk_map = status->link_fast_bitmap; |
---|
.. | .. |
---|
534 | 520 | int ret = 0; |
---|
535 | 521 | u32 intr; |
---|
536 | 522 | int loopcount = WL1271_IRQ_MAX_LOOPS; |
---|
| 523 | + bool run_tx_queue = true; |
---|
537 | 524 | bool done = false; |
---|
538 | 525 | unsigned int defer_count; |
---|
539 | 526 | unsigned long flags; |
---|
.. | .. |
---|
557 | 544 | } |
---|
558 | 545 | |
---|
559 | 546 | while (!done && loopcount--) { |
---|
560 | | - /* |
---|
561 | | - * In order to avoid a race with the hardirq, clear the flag |
---|
562 | | - * before acknowledging the chip. |
---|
563 | | - */ |
---|
564 | | - clear_bit(WL1271_FLAG_IRQ_RUNNING, &wl->flags); |
---|
565 | 547 | smp_mb__after_atomic(); |
---|
566 | 548 | |
---|
567 | 549 | ret = wlcore_fw_status(wl, wl->fw_status); |
---|
568 | 550 | if (ret < 0) |
---|
569 | | - goto out; |
---|
| 551 | + goto err_ret; |
---|
570 | 552 | |
---|
571 | 553 | wlcore_hw_tx_immediate_compl(wl); |
---|
572 | 554 | |
---|
.. | .. |
---|
583 | 565 | ret = -EIO; |
---|
584 | 566 | |
---|
585 | 567 | /* restarting the chip. ignore any other interrupt. */ |
---|
586 | | - goto out; |
---|
| 568 | + goto err_ret; |
---|
587 | 569 | } |
---|
588 | 570 | |
---|
589 | 571 | if (unlikely(intr & WL1271_ACX_SW_INTR_WATCHDOG)) { |
---|
.. | .. |
---|
593 | 575 | ret = -EIO; |
---|
594 | 576 | |
---|
595 | 577 | /* restarting the chip. ignore any other interrupt. */ |
---|
596 | | - goto out; |
---|
| 578 | + goto err_ret; |
---|
597 | 579 | } |
---|
598 | 580 | |
---|
599 | 581 | if (likely(intr & WL1271_ACX_INTR_DATA)) { |
---|
.. | .. |
---|
601 | 583 | |
---|
602 | 584 | ret = wlcore_rx(wl, wl->fw_status); |
---|
603 | 585 | if (ret < 0) |
---|
604 | | - goto out; |
---|
| 586 | + goto err_ret; |
---|
605 | 587 | |
---|
606 | 588 | /* Check if any tx blocks were freed */ |
---|
607 | | - spin_lock_irqsave(&wl->wl_lock, flags); |
---|
608 | | - if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags) && |
---|
609 | | - wl1271_tx_total_queue_count(wl) > 0) { |
---|
610 | | - spin_unlock_irqrestore(&wl->wl_lock, flags); |
---|
| 589 | + if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags)) { |
---|
| 590 | + if (spin_trylock_irqsave(&wl->wl_lock, flags)) { |
---|
| 591 | + if (!wl1271_tx_total_queue_count(wl)) |
---|
| 592 | + run_tx_queue = false; |
---|
| 593 | + spin_unlock_irqrestore(&wl->wl_lock, flags); |
---|
| 594 | + } |
---|
| 595 | + |
---|
611 | 596 | /* |
---|
612 | 597 | * In order to avoid starvation of the TX path, |
---|
613 | 598 | * call the work function directly. |
---|
614 | 599 | */ |
---|
615 | | - ret = wlcore_tx_work_locked(wl); |
---|
616 | | - if (ret < 0) |
---|
617 | | - goto out; |
---|
618 | | - } else { |
---|
619 | | - spin_unlock_irqrestore(&wl->wl_lock, flags); |
---|
| 600 | + if (run_tx_queue) { |
---|
| 601 | + ret = wlcore_tx_work_locked(wl); |
---|
| 602 | + if (ret < 0) |
---|
| 603 | + goto err_ret; |
---|
| 604 | + } |
---|
620 | 605 | } |
---|
621 | 606 | |
---|
622 | 607 | /* check for tx results */ |
---|
623 | 608 | ret = wlcore_hw_tx_delayed_compl(wl); |
---|
624 | 609 | if (ret < 0) |
---|
625 | | - goto out; |
---|
| 610 | + goto err_ret; |
---|
626 | 611 | |
---|
627 | 612 | /* Make sure the deferred queues don't get too long */ |
---|
628 | 613 | defer_count = skb_queue_len(&wl->deferred_tx_queue) + |
---|
.. | .. |
---|
635 | 620 | wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_A"); |
---|
636 | 621 | ret = wl1271_event_handle(wl, 0); |
---|
637 | 622 | if (ret < 0) |
---|
638 | | - goto out; |
---|
| 623 | + goto err_ret; |
---|
639 | 624 | } |
---|
640 | 625 | |
---|
641 | 626 | if (intr & WL1271_ACX_INTR_EVENT_B) { |
---|
642 | 627 | wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_B"); |
---|
643 | 628 | ret = wl1271_event_handle(wl, 1); |
---|
644 | 629 | if (ret < 0) |
---|
645 | | - goto out; |
---|
| 630 | + goto err_ret; |
---|
646 | 631 | } |
---|
647 | 632 | |
---|
648 | 633 | if (intr & WL1271_ACX_INTR_INIT_COMPLETE) |
---|
.. | .. |
---|
653 | 638 | wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_HW_AVAILABLE"); |
---|
654 | 639 | } |
---|
655 | 640 | |
---|
| 641 | +err_ret: |
---|
656 | 642 | pm_runtime_mark_last_busy(wl->dev); |
---|
657 | 643 | pm_runtime_put_autosuspend(wl->dev); |
---|
658 | 644 | |
---|
.. | .. |
---|
665 | 651 | int ret; |
---|
666 | 652 | unsigned long flags; |
---|
667 | 653 | struct wl1271 *wl = cookie; |
---|
| 654 | + bool queue_tx_work = true; |
---|
| 655 | + |
---|
| 656 | + set_bit(WL1271_FLAG_IRQ_RUNNING, &wl->flags); |
---|
668 | 657 | |
---|
669 | 658 | /* complete the ELP completion */ |
---|
670 | | - spin_lock_irqsave(&wl->wl_lock, flags); |
---|
671 | | - set_bit(WL1271_FLAG_IRQ_RUNNING, &wl->flags); |
---|
672 | | - if (wl->elp_compl) { |
---|
673 | | - complete(wl->elp_compl); |
---|
674 | | - wl->elp_compl = NULL; |
---|
| 659 | + if (test_bit(WL1271_FLAG_IN_ELP, &wl->flags)) { |
---|
| 660 | + spin_lock_irqsave(&wl->wl_lock, flags); |
---|
| 661 | + if (wl->elp_compl) |
---|
| 662 | + complete(wl->elp_compl); |
---|
| 663 | + spin_unlock_irqrestore(&wl->wl_lock, flags); |
---|
675 | 664 | } |
---|
676 | 665 | |
---|
677 | 666 | if (test_bit(WL1271_FLAG_SUSPENDED, &wl->flags)) { |
---|
678 | 667 | /* don't enqueue a work right now. mark it as pending */ |
---|
679 | 668 | set_bit(WL1271_FLAG_PENDING_WORK, &wl->flags); |
---|
680 | 669 | wl1271_debug(DEBUG_IRQ, "should not enqueue work"); |
---|
| 670 | + spin_lock_irqsave(&wl->wl_lock, flags); |
---|
681 | 671 | disable_irq_nosync(wl->irq); |
---|
682 | 672 | pm_wakeup_event(wl->dev, 0); |
---|
683 | 673 | spin_unlock_irqrestore(&wl->wl_lock, flags); |
---|
684 | | - return IRQ_HANDLED; |
---|
| 674 | + goto out_handled; |
---|
685 | 675 | } |
---|
686 | | - spin_unlock_irqrestore(&wl->wl_lock, flags); |
---|
687 | 676 | |
---|
688 | 677 | /* TX might be handled here, avoid redundant work */ |
---|
689 | 678 | set_bit(WL1271_FLAG_TX_PENDING, &wl->flags); |
---|
.. | .. |
---|
695 | 684 | if (ret) |
---|
696 | 685 | wl12xx_queue_recovery_work(wl); |
---|
697 | 686 | |
---|
698 | | - spin_lock_irqsave(&wl->wl_lock, flags); |
---|
699 | | - /* In case TX was not handled here, queue TX work */ |
---|
| 687 | + /* In case TX was not handled in wlcore_irq_locked(), queue TX work */ |
---|
700 | 688 | clear_bit(WL1271_FLAG_TX_PENDING, &wl->flags); |
---|
701 | | - if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags) && |
---|
702 | | - wl1271_tx_total_queue_count(wl) > 0) |
---|
703 | | - ieee80211_queue_work(wl->hw, &wl->tx_work); |
---|
704 | | - spin_unlock_irqrestore(&wl->wl_lock, flags); |
---|
| 689 | + if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags)) { |
---|
| 690 | + if (spin_trylock_irqsave(&wl->wl_lock, flags)) { |
---|
| 691 | + if (!wl1271_tx_total_queue_count(wl)) |
---|
| 692 | + queue_tx_work = false; |
---|
| 693 | + spin_unlock_irqrestore(&wl->wl_lock, flags); |
---|
| 694 | + } |
---|
| 695 | + if (queue_tx_work) |
---|
| 696 | + ieee80211_queue_work(wl->hw, &wl->tx_work); |
---|
| 697 | + } |
---|
705 | 698 | |
---|
706 | 699 | mutex_unlock(&wl->mutex); |
---|
| 700 | + |
---|
| 701 | +out_handled: |
---|
| 702 | + clear_bit(WL1271_FLAG_IRQ_RUNNING, &wl->flags); |
---|
707 | 703 | |
---|
708 | 704 | return IRQ_HANDLED; |
---|
709 | 705 | } |
---|
.. | .. |
---|
1447 | 1443 | |
---|
1448 | 1444 | field = &filter->fields[filter->num_fields]; |
---|
1449 | 1445 | |
---|
1450 | | - field->pattern = kzalloc(len, GFP_KERNEL); |
---|
| 1446 | + field->pattern = kmemdup(pattern, len, GFP_KERNEL); |
---|
1451 | 1447 | if (!field->pattern) { |
---|
1452 | 1448 | wl1271_warning("Failed to allocate RX filter pattern"); |
---|
1453 | 1449 | return -ENOMEM; |
---|
.. | .. |
---|
1458 | 1454 | field->offset = cpu_to_le16(offset); |
---|
1459 | 1455 | field->flags = flags; |
---|
1460 | 1456 | field->len = len; |
---|
1461 | | - memcpy(field->pattern, pattern, len); |
---|
1462 | 1457 | |
---|
1463 | 1458 | return 0; |
---|
1464 | 1459 | } |
---|
.. | .. |
---|
1760 | 1755 | |
---|
1761 | 1756 | ret = wl1271_configure_suspend(wl, wlvif, wow); |
---|
1762 | 1757 | if (ret < 0) { |
---|
1763 | | - mutex_unlock(&wl->mutex); |
---|
1764 | | - wl1271_warning("couldn't prepare device to suspend"); |
---|
1765 | | - return ret; |
---|
| 1758 | + goto out_sleep; |
---|
1766 | 1759 | } |
---|
1767 | 1760 | } |
---|
1768 | 1761 | |
---|
.. | .. |
---|
2712 | 2705 | |
---|
2713 | 2706 | if (!wlcore_is_p2p_mgmt(wlvif)) { |
---|
2714 | 2707 | ret = wl12xx_cmd_role_disable(wl, &wlvif->role_id); |
---|
2715 | | - if (ret < 0) |
---|
| 2708 | + if (ret < 0) { |
---|
| 2709 | + pm_runtime_put_noidle(wl->dev); |
---|
2716 | 2710 | goto deinit; |
---|
| 2711 | + } |
---|
2717 | 2712 | } else { |
---|
2718 | 2713 | ret = wl12xx_cmd_role_disable(wl, &wlvif->dev_role_id); |
---|
2719 | | - if (ret < 0) |
---|
| 2714 | + if (ret < 0) { |
---|
| 2715 | + pm_runtime_put_noidle(wl->dev); |
---|
2720 | 2716 | goto deinit; |
---|
| 2717 | + } |
---|
2721 | 2718 | } |
---|
2722 | 2719 | |
---|
2723 | 2720 | pm_runtime_mark_last_busy(wl->dev); |
---|
.. | .. |
---|
3274 | 3271 | static int wl1271_record_ap_key(struct wl1271 *wl, struct wl12xx_vif *wlvif, |
---|
3275 | 3272 | u8 id, u8 key_type, u8 key_size, |
---|
3276 | 3273 | const u8 *key, u8 hlid, u32 tx_seq_32, |
---|
3277 | | - u16 tx_seq_16) |
---|
| 3274 | + u16 tx_seq_16, bool is_pairwise) |
---|
3278 | 3275 | { |
---|
3279 | 3276 | struct wl1271_ap_key *ap_key; |
---|
3280 | 3277 | int i; |
---|
.. | .. |
---|
3312 | 3309 | ap_key->hlid = hlid; |
---|
3313 | 3310 | ap_key->tx_seq_32 = tx_seq_32; |
---|
3314 | 3311 | ap_key->tx_seq_16 = tx_seq_16; |
---|
| 3312 | + ap_key->is_pairwise = is_pairwise; |
---|
3315 | 3313 | |
---|
3316 | 3314 | wlvif->ap.recorded_keys[i] = ap_key; |
---|
3317 | 3315 | return 0; |
---|
.. | .. |
---|
3347 | 3345 | key->id, key->key_type, |
---|
3348 | 3346 | key->key_size, key->key, |
---|
3349 | 3347 | hlid, key->tx_seq_32, |
---|
3350 | | - key->tx_seq_16); |
---|
| 3348 | + key->tx_seq_16, key->is_pairwise); |
---|
3351 | 3349 | if (ret < 0) |
---|
3352 | 3350 | goto out; |
---|
3353 | 3351 | |
---|
.. | .. |
---|
3370 | 3368 | static int wl1271_set_key(struct wl1271 *wl, struct wl12xx_vif *wlvif, |
---|
3371 | 3369 | u16 action, u8 id, u8 key_type, |
---|
3372 | 3370 | u8 key_size, const u8 *key, u32 tx_seq_32, |
---|
3373 | | - u16 tx_seq_16, struct ieee80211_sta *sta) |
---|
| 3371 | + u16 tx_seq_16, struct ieee80211_sta *sta, |
---|
| 3372 | + bool is_pairwise) |
---|
3374 | 3373 | { |
---|
3375 | 3374 | int ret; |
---|
3376 | 3375 | bool is_ap = (wlvif->bss_type == BSS_TYPE_AP_BSS); |
---|
.. | .. |
---|
3397 | 3396 | ret = wl1271_record_ap_key(wl, wlvif, id, |
---|
3398 | 3397 | key_type, key_size, |
---|
3399 | 3398 | key, hlid, tx_seq_32, |
---|
3400 | | - tx_seq_16); |
---|
| 3399 | + tx_seq_16, is_pairwise); |
---|
3401 | 3400 | } else { |
---|
3402 | 3401 | ret = wl1271_cmd_set_ap_key(wl, wlvif, action, |
---|
3403 | 3402 | id, key_type, key_size, |
---|
3404 | 3403 | key, hlid, tx_seq_32, |
---|
3405 | | - tx_seq_16); |
---|
| 3404 | + tx_seq_16, is_pairwise); |
---|
3406 | 3405 | } |
---|
3407 | 3406 | |
---|
3408 | 3407 | if (ret < 0) |
---|
.. | .. |
---|
3502 | 3501 | u16 tx_seq_16 = 0; |
---|
3503 | 3502 | u8 key_type; |
---|
3504 | 3503 | u8 hlid; |
---|
| 3504 | + bool is_pairwise; |
---|
3505 | 3505 | |
---|
3506 | 3506 | wl1271_debug(DEBUG_MAC80211, "mac80211 set key"); |
---|
3507 | 3507 | |
---|
.. | .. |
---|
3551 | 3551 | return -EOPNOTSUPP; |
---|
3552 | 3552 | } |
---|
3553 | 3553 | |
---|
| 3554 | + is_pairwise = key_conf->flags & IEEE80211_KEY_FLAG_PAIRWISE; |
---|
| 3555 | + |
---|
3554 | 3556 | switch (cmd) { |
---|
3555 | 3557 | case SET_KEY: |
---|
3556 | 3558 | ret = wl1271_set_key(wl, wlvif, KEY_ADD_OR_REPLACE, |
---|
3557 | 3559 | key_conf->keyidx, key_type, |
---|
3558 | 3560 | key_conf->keylen, key_conf->key, |
---|
3559 | | - tx_seq_32, tx_seq_16, sta); |
---|
| 3561 | + tx_seq_32, tx_seq_16, sta, is_pairwise); |
---|
3560 | 3562 | if (ret < 0) { |
---|
3561 | 3563 | wl1271_error("Could not add or replace key"); |
---|
3562 | 3564 | return ret; |
---|
.. | .. |
---|
3582 | 3584 | ret = wl1271_set_key(wl, wlvif, KEY_REMOVE, |
---|
3583 | 3585 | key_conf->keyidx, key_type, |
---|
3584 | 3586 | key_conf->keylen, key_conf->key, |
---|
3585 | | - 0, 0, sta); |
---|
| 3587 | + 0, 0, sta, is_pairwise); |
---|
3586 | 3588 | if (ret < 0) { |
---|
3587 | 3589 | wl1271_error("Could not remove key"); |
---|
3588 | 3590 | return ret; |
---|
.. | .. |
---|
5751 | 5753 | ieee80211_remain_on_channel_expired(wl->hw); |
---|
5752 | 5754 | } |
---|
5753 | 5755 | |
---|
5754 | | -static int wlcore_op_cancel_remain_on_channel(struct ieee80211_hw *hw) |
---|
| 5756 | +static int wlcore_op_cancel_remain_on_channel(struct ieee80211_hw *hw, |
---|
| 5757 | + struct ieee80211_vif *vif) |
---|
5755 | 5758 | { |
---|
5756 | 5759 | struct wl1271 *wl = hw->priv; |
---|
5757 | 5760 | |
---|
.. | .. |
---|
6225 | 6228 | |
---|
6226 | 6229 | ieee80211_hw_set(wl->hw, SUPPORT_FAST_XMIT); |
---|
6227 | 6230 | ieee80211_hw_set(wl->hw, CHANCTX_STA_CSA); |
---|
| 6231 | + ieee80211_hw_set(wl->hw, SUPPORTS_PER_STA_GTK); |
---|
6228 | 6232 | ieee80211_hw_set(wl->hw, QUEUE_CONTROL); |
---|
6229 | 6233 | ieee80211_hw_set(wl->hw, TX_AMPDU_SETUP_IN_HW); |
---|
6230 | 6234 | ieee80211_hw_set(wl->hw, AMPDU_AGGREGATION); |
---|
.. | .. |
---|
6269 | 6273 | |
---|
6270 | 6274 | wl->hw->wiphy->flags |= WIPHY_FLAG_AP_UAPSD | |
---|
6271 | 6275 | WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL | |
---|
6272 | | - WIPHY_FLAG_HAS_CHANNEL_SWITCH; |
---|
| 6276 | + WIPHY_FLAG_HAS_CHANNEL_SWITCH | |
---|
| 6277 | + WIPHY_FLAG_IBSS_RSN; |
---|
6273 | 6278 | |
---|
6274 | 6279 | wl->hw->wiphy->features |= NL80211_FEATURE_AP_SCAN; |
---|
6275 | 6280 | |
---|
.. | .. |
---|
6619 | 6624 | } |
---|
6620 | 6625 | |
---|
6621 | 6626 | #ifdef CONFIG_PM |
---|
| 6627 | + device_init_wakeup(wl->dev, true); |
---|
| 6628 | + |
---|
6622 | 6629 | ret = enable_irq_wake(wl->irq); |
---|
6623 | 6630 | if (!ret) { |
---|
6624 | 6631 | wl->irq_wake_enabled = true; |
---|
6625 | | - device_init_wakeup(wl->dev, 1); |
---|
6626 | 6632 | if (pdev_data->pwr_in_suspend) |
---|
6627 | 6633 | wl->hw->wiphy->wowlan = &wlcore_wowlan_support; |
---|
| 6634 | + } |
---|
| 6635 | + |
---|
| 6636 | + res = platform_get_resource(pdev, IORESOURCE_IRQ, 1); |
---|
| 6637 | + if (res) { |
---|
| 6638 | + wl->wakeirq = res->start; |
---|
| 6639 | + wl->wakeirq_flags = res->flags & IRQF_TRIGGER_MASK; |
---|
| 6640 | + ret = dev_pm_set_dedicated_wake_irq(wl->dev, wl->wakeirq); |
---|
| 6641 | + if (ret) |
---|
| 6642 | + wl->wakeirq = -ENODEV; |
---|
| 6643 | + } else { |
---|
| 6644 | + wl->wakeirq = -ENODEV; |
---|
6628 | 6645 | } |
---|
6629 | 6646 | #endif |
---|
6630 | 6647 | disable_irq(wl->irq); |
---|
.. | .. |
---|
6653 | 6670 | wl1271_unregister_hw(wl); |
---|
6654 | 6671 | |
---|
6655 | 6672 | out_irq: |
---|
| 6673 | + if (wl->wakeirq >= 0) |
---|
| 6674 | + dev_pm_clear_wake_irq(wl->dev); |
---|
| 6675 | + device_init_wakeup(wl->dev, false); |
---|
6656 | 6676 | free_irq(wl->irq, wl); |
---|
6657 | 6677 | |
---|
6658 | 6678 | out_free_nvs: |
---|
.. | .. |
---|
6703 | 6723 | unsigned long flags; |
---|
6704 | 6724 | int ret; |
---|
6705 | 6725 | unsigned long start_time = jiffies; |
---|
6706 | | - bool pending = false; |
---|
6707 | 6726 | bool recovery = false; |
---|
6708 | 6727 | |
---|
6709 | 6728 | /* Nothing to do if no ELP mode requested */ |
---|
.. | .. |
---|
6713 | 6732 | wl1271_debug(DEBUG_PSM, "waking up chip from elp"); |
---|
6714 | 6733 | |
---|
6715 | 6734 | spin_lock_irqsave(&wl->wl_lock, flags); |
---|
6716 | | - if (test_bit(WL1271_FLAG_IRQ_RUNNING, &wl->flags)) |
---|
6717 | | - pending = true; |
---|
6718 | | - else |
---|
6719 | | - wl->elp_compl = &compl; |
---|
| 6735 | + wl->elp_compl = &compl; |
---|
6720 | 6736 | spin_unlock_irqrestore(&wl->wl_lock, flags); |
---|
6721 | 6737 | |
---|
6722 | 6738 | ret = wlcore_raw_write32(wl, HW_ACCESS_ELP_CTRL_REG, ELPCTRL_WAKE_UP); |
---|
6723 | 6739 | if (ret < 0) { |
---|
6724 | 6740 | recovery = true; |
---|
6725 | | - goto err; |
---|
6726 | | - } |
---|
6727 | | - |
---|
6728 | | - if (!pending) { |
---|
| 6741 | + } else if (!test_bit(WL1271_FLAG_IRQ_RUNNING, &wl->flags)) { |
---|
6729 | 6742 | ret = wait_for_completion_timeout(&compl, |
---|
6730 | 6743 | msecs_to_jiffies(WL1271_WAKEUP_TIMEOUT)); |
---|
6731 | 6744 | if (ret == 0) { |
---|
6732 | 6745 | wl1271_warning("ELP wakeup timeout!"); |
---|
6733 | | - |
---|
6734 | | - /* Return no error for runtime PM for recovery */ |
---|
6735 | | - ret = 0; |
---|
6736 | 6746 | recovery = true; |
---|
6737 | | - goto err; |
---|
6738 | 6747 | } |
---|
6739 | 6748 | } |
---|
6740 | 6749 | |
---|
6741 | | - clear_bit(WL1271_FLAG_IN_ELP, &wl->flags); |
---|
6742 | | - |
---|
6743 | | - wl1271_debug(DEBUG_PSM, "wakeup time: %u ms", |
---|
6744 | | - jiffies_to_msecs(jiffies - start_time)); |
---|
6745 | | - |
---|
6746 | | - return 0; |
---|
6747 | | - |
---|
6748 | | -err: |
---|
6749 | 6750 | spin_lock_irqsave(&wl->wl_lock, flags); |
---|
6750 | 6751 | wl->elp_compl = NULL; |
---|
6751 | 6752 | spin_unlock_irqrestore(&wl->wl_lock, flags); |
---|
| 6753 | + clear_bit(WL1271_FLAG_IN_ELP, &wl->flags); |
---|
6752 | 6754 | |
---|
6753 | 6755 | if (recovery) { |
---|
6754 | 6756 | set_bit(WL1271_FLAG_INTENDED_FW_RECOVERY, &wl->flags); |
---|
6755 | 6757 | wl12xx_queue_recovery_work(wl); |
---|
| 6758 | + } else { |
---|
| 6759 | + wl1271_debug(DEBUG_PSM, "wakeup time: %u ms", |
---|
| 6760 | + jiffies_to_msecs(jiffies - start_time)); |
---|
6756 | 6761 | } |
---|
6757 | 6762 | |
---|
6758 | | - return ret; |
---|
| 6763 | + return 0; |
---|
6759 | 6764 | } |
---|
6760 | 6765 | |
---|
6761 | 6766 | static const struct dev_pm_ops wlcore_pm_ops = { |
---|
.. | .. |
---|
6817 | 6822 | if (!wl->initialized) |
---|
6818 | 6823 | return 0; |
---|
6819 | 6824 | |
---|
6820 | | - if (wl->irq_wake_enabled) { |
---|
6821 | | - device_init_wakeup(wl->dev, 0); |
---|
6822 | | - disable_irq_wake(wl->irq); |
---|
| 6825 | + if (wl->wakeirq >= 0) { |
---|
| 6826 | + dev_pm_clear_wake_irq(wl->dev); |
---|
| 6827 | + wl->wakeirq = -ENODEV; |
---|
6823 | 6828 | } |
---|
| 6829 | + |
---|
| 6830 | + device_init_wakeup(wl->dev, false); |
---|
| 6831 | + |
---|
| 6832 | + if (wl->irq_wake_enabled) |
---|
| 6833 | + disable_irq_wake(wl->irq); |
---|
| 6834 | + |
---|
6824 | 6835 | wl1271_unregister_hw(wl); |
---|
6825 | 6836 | |
---|
6826 | 6837 | pm_runtime_put_sync(wl->dev); |
---|