During suspend, there are a few scan enable and set event filter
commands that don't need to be sent unless there are actual BR/EDR
devices capable of waking the system. Check the HCI_PSCAN bit before
writing scan enable and use a new dev flag, HCI_EVENT_FILTER_CONFIGURED
to control whether to clear the event filter.

Signed-off-by: Abhishek Pandit-Subedi <abhishekpan...@chromium.org>
Reviewed-by: Archie Pusaka <apus...@chromium.org>
Reviewed-by: Alain Michaud <ala...@chromium.org>
---

Changes in v3:
* Minor change to if statement

Changes in v2:
* Removed hci_dev_lock from hci_cc_set_event_filter since flags are
  set/cleared atomically

 include/net/bluetooth/hci.h |  1 +
 net/bluetooth/hci_event.c   | 27 +++++++++++++++++++++++
 net/bluetooth/hci_request.c | 44 +++++++++++++++++++++++--------------
 3 files changed, 55 insertions(+), 17 deletions(-)

diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h
index ba2f439bc04d34..ea4ae551c42687 100644
--- a/include/net/bluetooth/hci.h
+++ b/include/net/bluetooth/hci.h
@@ -320,6 +320,7 @@ enum {
        HCI_BREDR_ENABLED,
        HCI_LE_SCAN_INTERRUPTED,
        HCI_WIDEBAND_SPEECH_ENABLED,
+       HCI_EVENT_FILTER_CONFIGURED,
 
        HCI_DUT_MODE,
        HCI_VENDOR_DIAG,
diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
index 67668be3461e93..f4a734f8a9ac88 100644
--- a/net/bluetooth/hci_event.c
+++ b/net/bluetooth/hci_event.c
@@ -395,6 +395,29 @@ static void hci_cc_write_scan_enable(struct hci_dev *hdev, 
struct sk_buff *skb)
        hci_dev_unlock(hdev);
 }
 
+static void hci_cc_set_event_filter(struct hci_dev *hdev, struct sk_buff *skb)
+{
+       __u8 status = *((__u8 *)skb->data);
+       struct hci_cp_set_event_filter *cp;
+       void *sent;
+
+       BT_DBG("%s status 0x%2.2x", hdev->name, status);
+
+       if (status)
+               return;
+
+       sent = hci_sent_cmd_data(hdev, HCI_OP_SET_EVENT_FLT);
+       if (!sent)
+               return;
+
+       cp = (struct hci_cp_set_event_filter *)sent;
+
+       if (cp->flt_type == HCI_FLT_CLEAR_ALL)
+               hci_dev_clear_flag(hdev, HCI_EVENT_FILTER_CONFIGURED);
+       else
+               hci_dev_set_flag(hdev, HCI_EVENT_FILTER_CONFIGURED);
+}
+
 static void hci_cc_read_class_of_dev(struct hci_dev *hdev, struct sk_buff *skb)
 {
        struct hci_rp_read_class_of_dev *rp = (void *) skb->data;
@@ -3328,6 +3351,10 @@ static void hci_cmd_complete_evt(struct hci_dev *hdev, 
struct sk_buff *skb,
                hci_cc_write_scan_enable(hdev, skb);
                break;
 
+       case HCI_OP_SET_EVENT_FLT:
+               hci_cc_set_event_filter(hdev, skb);
+               break;
+
        case HCI_OP_READ_CLASS_OF_DEV:
                hci_cc_read_class_of_dev(hdev, skb);
                break;
diff --git a/net/bluetooth/hci_request.c b/net/bluetooth/hci_request.c
index e55976db4403e7..75a42178c82d9b 100644
--- a/net/bluetooth/hci_request.c
+++ b/net/bluetooth/hci_request.c
@@ -1131,14 +1131,14 @@ static void hci_req_clear_event_filter(struct 
hci_request *req)
 {
        struct hci_cp_set_event_filter f;
 
-       memset(&f, 0, sizeof(f));
-       f.flt_type = HCI_FLT_CLEAR_ALL;
-       hci_req_add(req, HCI_OP_SET_EVENT_FLT, 1, &f);
+       if (!hci_dev_test_flag(req->hdev, HCI_BREDR_ENABLED))
+               return;
 
-       /* Update page scan state (since we may have modified it when setting
-        * the event filter).
-        */
-       __hci_req_update_scan(req);
+       if (hci_dev_test_flag(req->hdev, HCI_EVENT_FILTER_CONFIGURED)) {
+               memset(&f, 0, sizeof(f));
+               f.flt_type = HCI_FLT_CLEAR_ALL;
+               hci_req_add(req, HCI_OP_SET_EVENT_FLT, 1, &f);
+       }
 }
 
 static void hci_req_set_event_filter(struct hci_request *req)
@@ -1147,6 +1147,10 @@ static void hci_req_set_event_filter(struct hci_request 
*req)
        struct hci_cp_set_event_filter f;
        struct hci_dev *hdev = req->hdev;
        u8 scan = SCAN_DISABLED;
+       bool scanning = test_bit(HCI_PSCAN, &hdev->flags);
+
+       if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED))
+               return;
 
        /* Always clear event filter when starting */
        hci_req_clear_event_filter(req);
@@ -1167,12 +1171,13 @@ static void hci_req_set_event_filter(struct hci_request 
*req)
                scan = SCAN_PAGE;
        }
 
-       if (scan)
+       if (scan && !scanning) {
                set_bit(SUSPEND_SCAN_ENABLE, hdev->suspend_tasks);
-       else
+               hci_req_add(req, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
+       } else if (!scan && scanning) {
                set_bit(SUSPEND_SCAN_DISABLE, hdev->suspend_tasks);
-
-       hci_req_add(req, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
+               hci_req_add(req, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
+       }
 }
 
 static void cancel_adv_timeout(struct hci_dev *hdev)
@@ -1315,9 +1320,14 @@ void hci_req_prepare_suspend(struct hci_dev *hdev, enum 
suspended_state next)
 
                hdev->advertising_paused = true;
                hdev->advertising_old_state = old_state;
-               /* Disable page scan */
-               page_scan = SCAN_DISABLED;
-               hci_req_add(&req, HCI_OP_WRITE_SCAN_ENABLE, 1, &page_scan);
+
+               /* Disable page scan if enabled */
+               if (test_bit(HCI_PSCAN, &hdev->flags)) {
+                       page_scan = SCAN_DISABLED;
+                       hci_req_add(&req, HCI_OP_WRITE_SCAN_ENABLE, 1,
+                                   &page_scan);
+                       set_bit(SUSPEND_SCAN_DISABLE, hdev->suspend_tasks);
+               }
 
                /* Disable LE passive scan if enabled */
                if (hci_dev_test_flag(hdev, HCI_LE_SCAN)) {
@@ -1328,9 +1338,6 @@ void hci_req_prepare_suspend(struct hci_dev *hdev, enum 
suspended_state next)
                /* Disable advertisement filters */
                hci_req_add_set_adv_filter_enable(&req, false);
 
-               /* Mark task needing completion */
-               set_bit(SUSPEND_SCAN_DISABLE, hdev->suspend_tasks);
-
                /* Prevent disconnects from causing scanning to be re-enabled */
                hdev->scanning_paused = true;
 
@@ -1364,7 +1371,10 @@ void hci_req_prepare_suspend(struct hci_dev *hdev, enum 
suspended_state next)
                hdev->suspended = false;
                hdev->scanning_paused = false;
 
+               /* Clear any event filters and restore scan state */
                hci_req_clear_event_filter(&req);
+               __hci_req_update_scan(&req);
+
                /* Reset passive/background scanning to normal */
                __hci_update_background_scan(&req);
                /* Enable all of the advertisement filters */
-- 
2.31.0.rc0.254.gbdcc3b1a9d-goog

Reply via email to