Bluetooth: Use controller sets when available
authorLuiz Augusto von Dentz <luiz.von.dentz@intel.com>
Mon, 3 Jun 2019 10:48:42 +0000 (13:48 +0300)
committerMarcel Holtmann <marcel@holtmann.org>
Sat, 6 Jul 2019 13:38:18 +0000 (15:38 +0200)
This makes use of controller sets when using Extended Advertising
feature thus offloading the scheduling to the controller.

Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
net/bluetooth/hci_conn.c
net/bluetooth/hci_core.c
net/bluetooth/hci_request.c
net/bluetooth/hci_request.h

index 17e5111..ad5b0ac 100644 (file)
@@ -915,7 +915,7 @@ static void hci_req_directed_advertising(struct hci_request *req,
                                    sizeof(cp), &cp);
                }
 
-               __hci_req_enable_ext_advertising(req);
+               __hci_req_enable_ext_advertising(req, 0x00);
        } else {
                struct hci_cp_le_set_adv_param cp;
 
index ff9a755..b9585e7 100644 (file)
@@ -2827,7 +2827,7 @@ int hci_add_adv_instance(struct hci_dev *hdev, u8 instance, u32 flags,
                memset(adv_instance->scan_rsp_data, 0,
                       sizeof(adv_instance->scan_rsp_data));
        } else {
-               if (hdev->adv_instance_cnt >= HCI_MAX_ADV_INSTANCES ||
+               if (hdev->adv_instance_cnt >= hdev->le_num_of_adv_sets ||
                    instance < 1 || instance > HCI_MAX_ADV_INSTANCES)
                        return -EOVERFLOW;
 
@@ -3195,6 +3195,7 @@ struct hci_dev *hci_alloc_dev(void)
        hdev->le_min_key_size = SMP_MIN_ENC_KEY_SIZE;
        hdev->le_tx_def_phys = HCI_LE_SET_PHY_1M;
        hdev->le_rx_def_phys = HCI_LE_SET_PHY_1M;
+       hdev->le_num_of_adv_sets = HCI_MAX_ADV_INSTANCES;
 
        hdev->rpa_timeout = HCI_DEFAULT_RPA_TIMEOUT;
        hdev->discov_interleaved_timeout = DISCOV_INTERLEAVED_TIMEOUT;
index e9a95ed..621f1a9 100644 (file)
@@ -1601,7 +1601,7 @@ int __hci_req_setup_ext_adv_instance(struct hci_request *req, u8 instance)
        cp.own_addr_type = own_addr_type;
        cp.channel_map = hdev->le_adv_channel_map;
        cp.tx_power = 127;
-       cp.handle = 0;
+       cp.handle = instance;
 
        if (flags & MGMT_ADV_FLAG_SEC_2M) {
                cp.primary_phy = HCI_ADV_PHY_1M;
@@ -1643,11 +1643,21 @@ int __hci_req_setup_ext_adv_instance(struct hci_request *req, u8 instance)
        return 0;
 }
 
-void __hci_req_enable_ext_advertising(struct hci_request *req)
+int __hci_req_enable_ext_advertising(struct hci_request *req, u8 instance)
 {
+       struct hci_dev *hdev = req->hdev;
        struct hci_cp_le_set_ext_adv_enable *cp;
        struct hci_cp_ext_adv_set *adv_set;
        u8 data[sizeof(*cp) + sizeof(*adv_set) * 1];
+       struct adv_info *adv_instance;
+
+       if (instance > 0) {
+               adv_instance = hci_find_adv_instance(hdev, instance);
+               if (!adv_instance)
+                       return -EINVAL;
+       } else {
+               adv_instance = NULL;
+       }
 
        cp = (void *) data;
        adv_set = (void *) cp->data;
@@ -1659,11 +1669,23 @@ void __hci_req_enable_ext_advertising(struct hci_request *req)
 
        memset(adv_set, 0, sizeof(*adv_set));
 
-       adv_set->handle = 0;
+       adv_set->handle = instance;
+
+       /* Set duration per instance since controller is responsible for
+        * scheduling it.
+        */
+       if (adv_instance && adv_instance->duration) {
+               u16 duration = adv_instance->duration * MSEC_PER_SEC;
+
+               /* Time = N * 10 ms */
+               adv_set->duration = cpu_to_le16(duration / 10);
+       }
 
        hci_req_add(req, HCI_OP_LE_SET_EXT_ADV_ENABLE,
                    sizeof(*cp) + sizeof(*adv_set) * cp->num_of_sets,
                    data);
+
+       return 0;
 }
 
 int __hci_req_start_ext_adv(struct hci_request *req, u8 instance)
@@ -1679,7 +1701,7 @@ int __hci_req_start_ext_adv(struct hci_request *req, u8 instance)
                return err;
 
        __hci_req_update_scan_rsp_data(req, instance);
-       __hci_req_enable_ext_advertising(req);
+       __hci_req_enable_ext_advertising(req, instance);
 
        return 0;
 }
@@ -1723,10 +1745,13 @@ int __hci_req_schedule_adv_instance(struct hci_request *req, u8 instance,
                adv_instance->remaining_time =
                                adv_instance->remaining_time - timeout;
 
-       hdev->adv_instance_timeout = timeout;
-       queue_delayed_work(hdev->req_workqueue,
+       /* Only use work for scheduling instances with legacy advertising */
+       if (!ext_adv_capable(hdev)) {
+               hdev->adv_instance_timeout = timeout;
+               queue_delayed_work(hdev->req_workqueue,
                           &hdev->adv_instance_expire,
                           msecs_to_jiffies(timeout * 1000));
+       }
 
        /* If we're just re-scheduling the same instance again then do not
         * execute any HCI commands. This happens when a single instance is
@@ -2744,7 +2769,8 @@ static int powered_update_hci(struct hci_request *req, unsigned long opt)
                                if (!ext_adv_capable(hdev))
                                        __hci_req_enable_advertising(req);
                                else if (!err)
-                                       __hci_req_enable_ext_advertising(req);
+                                       __hci_req_enable_ext_advertising(req,
+                                                                        0x00);
                        }
                } else if (!list_empty(&hdev->adv_instances)) {
                        struct adv_info *adv_instance;
index 55b2050..a7019fb 100644 (file)
@@ -83,7 +83,7 @@ void hci_req_clear_adv_instance(struct hci_dev *hdev, struct sock *sk,
 
 int __hci_req_setup_ext_adv_instance(struct hci_request *req, u8 instance);
 int __hci_req_start_ext_adv(struct hci_request *req, u8 instance);
-void __hci_req_enable_ext_advertising(struct hci_request *req);
+int __hci_req_enable_ext_advertising(struct hci_request *req, u8 instance);
 void __hci_req_clear_ext_adv_sets(struct hci_request *req);
 int hci_get_random_address(struct hci_dev *hdev, bool require_privacy,
                           bool use_rpa, struct adv_info *adv_instance,