Merge tag 'clk-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/clk/linux
[linux-2.6-microblaze.git] / net / bluetooth / hci_request.c
index 71bffd7..e55976d 100644 (file)
@@ -29,6 +29,7 @@
 
 #include "smp.h"
 #include "hci_request.h"
+#include "msft.h"
 
 #define HCI_REQ_DONE     0
 #define HCI_REQ_PEND     1
@@ -404,13 +405,18 @@ static void cancel_interleave_scan(struct hci_dev *hdev)
  */
 static bool __hci_update_interleaved_scan(struct hci_dev *hdev)
 {
-       /* If there is at least one ADV monitors and one pending LE connection
-        * or one device to be scanned for, we should alternate between
-        * allowlist scan and one without any filters to save power.
+       /* Do interleaved scan only if all of the following are true:
+        * - There is at least one ADV monitor
+        * - At least one pending LE connection or one device to be scanned for
+        * - Monitor offloading is not supported
+        * If so, we should alternate between allowlist scan and one without
+        * any filters to save power.
         */
        bool use_interleaving = hci_is_adv_monitoring(hdev) &&
                                !(list_empty(&hdev->pend_le_conns) &&
-                                 list_empty(&hdev->pend_le_reports));
+                                 list_empty(&hdev->pend_le_reports)) &&
+                               hci_get_adv_monitor_offload_ext(hdev) ==
+                                   HCI_ADV_MONITOR_EXT_NONE;
        bool is_interleaving = is_interleave_scanning(hdev);
 
        if (use_interleaving && !is_interleaving) {
@@ -899,14 +905,11 @@ static u8 update_white_list(struct hci_request *req)
 
        /* Use the allowlist unless the following conditions are all true:
         * - We are not currently suspending
-        * - There are 1 or more ADV monitors registered
+        * - There are 1 or more ADV monitors registered and it's not offloaded
         * - Interleaved scanning is not currently using the allowlist
-        *
-        * Once the controller offloading of advertisement monitor is in place,
-        * the above condition should include the support of MSFT extension
-        * support.
         */
        if (!idr_is_empty(&hdev->adv_monitors_idr) && !hdev->suspended &&
+           hci_get_adv_monitor_offload_ext(hdev) == HCI_ADV_MONITOR_EXT_NONE &&
            hdev->interleave_scan_state != INTERLEAVE_SCAN_ALLOWLIST)
                return 0x00;
 
@@ -1087,6 +1090,8 @@ void hci_req_add_le_passive_scan(struct hci_request *req)
        if (hdev->suspended) {
                window = hdev->le_scan_window_suspend;
                interval = hdev->le_scan_int_suspend;
+
+               set_bit(SUSPEND_SCAN_ENABLE, hdev->suspend_tasks);
        } else if (hci_is_le_conn_scanning(hdev)) {
                window = hdev->le_scan_window_connect;
                interval = hdev->le_scan_int_connect;
@@ -1170,19 +1175,6 @@ static void hci_req_set_event_filter(struct hci_request *req)
        hci_req_add(req, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
 }
 
-static void hci_req_config_le_suspend_scan(struct hci_request *req)
-{
-       /* Before changing params disable scan if enabled */
-       if (hci_dev_test_flag(req->hdev, HCI_LE_SCAN))
-               hci_req_add_le_scan_disable(req, false);
-
-       /* Configure params and enable scanning */
-       hci_req_add_le_passive_scan(req);
-
-       /* Block suspend notifier on response */
-       set_bit(SUSPEND_SCAN_ENABLE, req->hdev->suspend_tasks);
-}
-
 static void cancel_adv_timeout(struct hci_dev *hdev)
 {
        if (hdev->adv_instance_timeout) {
@@ -1245,12 +1237,37 @@ static void suspend_req_complete(struct hci_dev *hdev, u8 status, u16 opcode)
 {
        bt_dev_dbg(hdev, "Request complete opcode=0x%x, status=0x%x", opcode,
                   status);
-       if (test_and_clear_bit(SUSPEND_SCAN_ENABLE, hdev->suspend_tasks) ||
-           test_and_clear_bit(SUSPEND_SCAN_DISABLE, hdev->suspend_tasks)) {
+       if (test_bit(SUSPEND_SCAN_ENABLE, hdev->suspend_tasks) ||
+           test_bit(SUSPEND_SCAN_DISABLE, hdev->suspend_tasks)) {
+               clear_bit(SUSPEND_SCAN_ENABLE, hdev->suspend_tasks);
+               clear_bit(SUSPEND_SCAN_DISABLE, hdev->suspend_tasks);
+               wake_up(&hdev->suspend_wait_q);
+       }
+
+       if (test_bit(SUSPEND_SET_ADV_FILTER, hdev->suspend_tasks)) {
+               clear_bit(SUSPEND_SET_ADV_FILTER, hdev->suspend_tasks);
                wake_up(&hdev->suspend_wait_q);
        }
 }
 
+static void hci_req_add_set_adv_filter_enable(struct hci_request *req,
+                                             bool enable)
+{
+       struct hci_dev *hdev = req->hdev;
+
+       switch (hci_get_adv_monitor_offload_ext(hdev)) {
+       case HCI_ADV_MONITOR_EXT_MSFT:
+               msft_req_add_set_filter_enable(req, enable);
+               break;
+       default:
+               return;
+       }
+
+       /* No need to block when enabling since it's on resume path */
+       if (hdev->suspended && !enable)
+               set_bit(SUSPEND_SET_ADV_FILTER, hdev->suspend_tasks);
+}
+
 /* Call with hci_dev_lock */
 void hci_req_prepare_suspend(struct hci_dev *hdev, enum suspended_state next)
 {
@@ -1308,6 +1325,9 @@ void hci_req_prepare_suspend(struct hci_dev *hdev, enum suspended_state next)
                        hci_req_add_le_scan_disable(&req, false);
                }
 
+               /* Disable advertisement filters */
+               hci_req_add_set_adv_filter_enable(&req, false);
+
                /* Mark task needing completion */
                set_bit(SUSPEND_SCAN_DISABLE, hdev->suspend_tasks);
 
@@ -1336,7 +1356,7 @@ void hci_req_prepare_suspend(struct hci_dev *hdev, enum suspended_state next)
                /* Enable event filter for paired devices */
                hci_req_set_event_filter(&req);
                /* Enable passive scan at lower duty cycle */
-               hci_req_config_le_suspend_scan(&req);
+               __hci_update_background_scan(&req);
                /* Pause scan changes again. */
                hdev->scanning_paused = true;
                hci_req_run(&req, suspend_req_complete);
@@ -1346,7 +1366,9 @@ void hci_req_prepare_suspend(struct hci_dev *hdev, enum suspended_state next)
 
                hci_req_clear_event_filter(&req);
                /* Reset passive/background scanning to normal */
-               hci_req_config_le_suspend_scan(&req);
+               __hci_update_background_scan(&req);
+               /* Enable all of the advertisement filters */
+               hci_req_add_set_adv_filter_enable(&req, true);
 
                /* Unpause directed advertising */
                hdev->advertising_paused = false;