forked from mirrors/linux
		
	Bluetooth: Use controller sets when available
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>
This commit is contained in:
		
							parent
							
								
									c49a8682fc
								
							
						
					
					
						commit
						1d0fac2c38
					
				
					 4 changed files with 37 additions and 10 deletions
				
			
		|  | @ -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; | ||||
| 
 | ||||
|  |  | |||
|  | @ -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; | ||||
|  |  | |||
|  | @ -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; | ||||
| 
 | ||||
| 	/* 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; | ||||
|  |  | |||
|  | @ -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, | ||||
|  |  | |||
		Loading…
	
		Reference in a new issue
	
	 Luiz Augusto von Dentz
						Luiz Augusto von Dentz