Bluetooth: Rework le_scan_restart for hci_sync
authorBrian Gix <brian.gix@intel.com>
Fri, 5 Aug 2022 23:42:29 +0000 (16:42 -0700)
committerLuiz Augusto von Dentz <luiz.von.dentz@intel.com>
Thu, 25 Aug 2022 23:18:54 +0000 (16:18 -0700)
le_scan_restart delayed work queue was running as a deprecated
hci_request instead of on the newer thread-safe hci_sync mechanism.

Signed-off-by: Brian Gix <brian.gix@intel.com>
Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
net/bluetooth/hci_request.c
net/bluetooth/hci_sync.c

index 32fefaa0d3caa044ea484dfc642aa303dc36f13a..114af73503636780a411de1d192922a0808c84c1 100644 (file)
@@ -1975,92 +1975,6 @@ int hci_abort_conn(struct hci_conn *conn, u8 reason)
        return 0;
 }
 
-static int le_scan_restart(struct hci_request *req, unsigned long opt)
-{
-       struct hci_dev *hdev = req->hdev;
-
-       /* If controller is not scanning we are done. */
-       if (!hci_dev_test_flag(hdev, HCI_LE_SCAN))
-               return 0;
-
-       if (hdev->scanning_paused) {
-               bt_dev_dbg(hdev, "Scanning is paused for suspend");
-               return 0;
-       }
-
-       hci_req_add_le_scan_disable(req, false);
-
-       if (use_ext_scan(hdev)) {
-               struct hci_cp_le_set_ext_scan_enable ext_enable_cp;
-
-               memset(&ext_enable_cp, 0, sizeof(ext_enable_cp));
-               ext_enable_cp.enable = LE_SCAN_ENABLE;
-               ext_enable_cp.filter_dup = LE_SCAN_FILTER_DUP_ENABLE;
-
-               hci_req_add(req, HCI_OP_LE_SET_EXT_SCAN_ENABLE,
-                           sizeof(ext_enable_cp), &ext_enable_cp);
-       } else {
-               struct hci_cp_le_set_scan_enable cp;
-
-               memset(&cp, 0, sizeof(cp));
-               cp.enable = LE_SCAN_ENABLE;
-               cp.filter_dup = LE_SCAN_FILTER_DUP_ENABLE;
-               hci_req_add(req, HCI_OP_LE_SET_SCAN_ENABLE, sizeof(cp), &cp);
-       }
-
-       return 0;
-}
-
-static void le_scan_restart_work(struct work_struct *work)
-{
-       struct hci_dev *hdev = container_of(work, struct hci_dev,
-                                           le_scan_restart.work);
-       unsigned long timeout, duration, scan_start, now;
-       u8 status;
-
-       bt_dev_dbg(hdev, "");
-
-       hci_req_sync(hdev, le_scan_restart, 0, HCI_CMD_TIMEOUT, &status);
-       if (status) {
-               bt_dev_err(hdev, "failed to restart LE scan: status %d",
-                          status);
-               return;
-       }
-
-       hci_dev_lock(hdev);
-
-       if (!test_bit(HCI_QUIRK_STRICT_DUPLICATE_FILTER, &hdev->quirks) ||
-           !hdev->discovery.scan_start)
-               goto unlock;
-
-       /* When the scan was started, hdev->le_scan_disable has been queued
-        * after duration from scan_start. During scan restart this job
-        * has been canceled, and we need to queue it again after proper
-        * timeout, to make sure that scan does not run indefinitely.
-        */
-       duration = hdev->discovery.scan_duration;
-       scan_start = hdev->discovery.scan_start;
-       now = jiffies;
-       if (now - scan_start <= duration) {
-               int elapsed;
-
-               if (now >= scan_start)
-                       elapsed = now - scan_start;
-               else
-                       elapsed = ULONG_MAX - scan_start + now;
-
-               timeout = duration - elapsed;
-       } else {
-               timeout = 0;
-       }
-
-       queue_delayed_work(hdev->req_workqueue,
-                          &hdev->le_scan_disable, timeout);
-
-unlock:
-       hci_dev_unlock(hdev);
-}
-
 bool hci_req_stop_discovery(struct hci_request *req)
 {
        struct hci_dev *hdev = req->hdev;
@@ -2158,7 +2072,6 @@ error:
 
 void hci_request_setup(struct hci_dev *hdev)
 {
-       INIT_DELAYED_WORK(&hdev->le_scan_restart, le_scan_restart_work);
        INIT_DELAYED_WORK(&hdev->adv_instance_expire, adv_timeout_expire);
        INIT_DELAYED_WORK(&hdev->interleave_scan, interleave_scan_work);
 }
@@ -2167,8 +2080,6 @@ void hci_request_cancel_all(struct hci_dev *hdev)
 {
        __hci_cmd_sync_cancel(hdev, ENODEV);
 
-       cancel_delayed_work_sync(&hdev->le_scan_restart);
-
        if (hdev->adv_instance_timeout) {
                cancel_delayed_work_sync(&hdev->adv_instance_expire);
                hdev->adv_instance_timeout = 0;
index e22837510ab12ee38d496f1ffc90d509f28f52c7..75e7c0a01ab18a9d9ea2c33a0216eb8a07126ccb 100644 (file)
@@ -392,6 +392,79 @@ _return:
        hci_dev_unlock(hdev);
 }
 
+static int hci_le_set_scan_enable_sync(struct hci_dev *hdev, u8 val,
+                                      u8 filter_dup);
+static int hci_le_scan_restart_sync(struct hci_dev *hdev)
+{
+       /* If controller is not scanning we are done. */
+       if (!hci_dev_test_flag(hdev, HCI_LE_SCAN))
+               return 0;
+
+       if (hdev->scanning_paused) {
+               bt_dev_dbg(hdev, "Scanning is paused for suspend");
+               return 0;
+       }
+
+       hci_le_set_scan_enable_sync(hdev, LE_SCAN_DISABLE, 0x00);
+       return hci_le_set_scan_enable_sync(hdev, LE_SCAN_ENABLE,
+                                          LE_SCAN_FILTER_DUP_ENABLE);
+}
+
+static int le_scan_restart_sync(struct hci_dev *hdev, void *data)
+{
+       return hci_le_scan_restart_sync(hdev);
+}
+
+static void le_scan_restart(struct work_struct *work)
+{
+       struct hci_dev *hdev = container_of(work, struct hci_dev,
+                                           le_scan_restart.work);
+       unsigned long timeout, duration, scan_start, now;
+       int status;
+
+       bt_dev_dbg(hdev, "");
+
+       hci_dev_lock(hdev);
+
+       status = hci_cmd_sync_queue(hdev, le_scan_restart_sync, NULL, NULL);
+       if (status) {
+               bt_dev_err(hdev, "failed to restart LE scan: status %d",
+                          status);
+               goto unlock;
+       }
+
+       if (!test_bit(HCI_QUIRK_STRICT_DUPLICATE_FILTER, &hdev->quirks) ||
+           !hdev->discovery.scan_start)
+               goto unlock;
+
+       /* When the scan was started, hdev->le_scan_disable has been queued
+        * after duration from scan_start. During scan restart this job
+        * has been canceled, and we need to queue it again after proper
+        * timeout, to make sure that scan does not run indefinitely.
+        */
+       duration = hdev->discovery.scan_duration;
+       scan_start = hdev->discovery.scan_start;
+       now = jiffies;
+       if (now - scan_start <= duration) {
+               int elapsed;
+
+               if (now >= scan_start)
+                       elapsed = now - scan_start;
+               else
+                       elapsed = ULONG_MAX - scan_start + now;
+
+               timeout = duration - elapsed;
+       } else {
+               timeout = 0;
+       }
+
+       queue_delayed_work(hdev->req_workqueue,
+                          &hdev->le_scan_disable, timeout);
+
+unlock:
+       hci_dev_unlock(hdev);
+}
+
 void hci_cmd_sync_init(struct hci_dev *hdev)
 {
        INIT_WORK(&hdev->cmd_sync_work, hci_cmd_sync_work);
@@ -400,6 +473,7 @@ void hci_cmd_sync_init(struct hci_dev *hdev)
 
        INIT_WORK(&hdev->cmd_sync_cancel_work, hci_cmd_sync_cancel_work);
        INIT_DELAYED_WORK(&hdev->le_scan_disable, le_scan_disable);
+       INIT_DELAYED_WORK(&hdev->le_scan_restart, le_scan_restart);
 }
 
 void hci_cmd_sync_clear(struct hci_dev *hdev)
@@ -4488,6 +4562,7 @@ int hci_dev_close_sync(struct hci_dev *hdev)
        cancel_delayed_work(&hdev->power_off);
        cancel_delayed_work(&hdev->ncmd_timer);
        cancel_delayed_work(&hdev->le_scan_disable);
+       cancel_delayed_work(&hdev->le_scan_restart);
 
        hci_request_cancel_all(hdev);