1 /*
2 * Copyright 2020 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include "hci/acl_manager/round_robin_scheduler.h"
18
19 #include <bluetooth/log.h>
20
21 #include "hci/acl_manager/acl_fragmenter.h"
22 namespace bluetooth {
23 namespace hci {
24 namespace acl_manager {
25
RoundRobinScheduler(os::Handler * handler,Controller * controller,common::BidiQueueEnd<AclBuilder,AclView> * hci_queue_end)26 RoundRobinScheduler::RoundRobinScheduler(
27 os::Handler* handler, Controller* controller, common::BidiQueueEnd<AclBuilder, AclView>* hci_queue_end)
28 : handler_(handler), controller_(controller), hci_queue_end_(hci_queue_end) {
29 max_acl_packet_credits_ = controller_->GetNumAclPacketBuffers();
30 acl_packet_credits_ = max_acl_packet_credits_;
31 hci_mtu_ = controller_->GetAclPacketLength();
32 LeBufferSize le_buffer_size = controller_->GetLeBufferSize();
33 le_max_acl_packet_credits_ = le_buffer_size.total_num_le_packets_;
34 le_acl_packet_credits_ = le_max_acl_packet_credits_;
35 le_hci_mtu_ = le_buffer_size.le_data_packet_length_;
36 controller_->RegisterCompletedAclPacketsCallback(handler->BindOn(this, &RoundRobinScheduler::incoming_acl_credits));
37 }
38
~RoundRobinScheduler()39 RoundRobinScheduler::~RoundRobinScheduler() {
40 unregister_all_connections();
41 controller_->UnregisterCompletedAclPacketsCallback();
42 }
43
Register(ConnectionType connection_type,uint16_t handle,std::shared_ptr<acl_manager::AclConnection::Queue> queue)44 void RoundRobinScheduler::Register(ConnectionType connection_type, uint16_t handle,
45 std::shared_ptr<acl_manager::AclConnection::Queue> queue) {
46 log::assert_that(
47 acl_queue_handlers_.count(handle) == 0,
48 "assert failed: acl_queue_handlers_.count(handle) == 0");
49 acl_queue_handler acl_queue_handler = {connection_type, std::move(queue), false, 0};
50 acl_queue_handlers_.insert(std::pair<uint16_t, RoundRobinScheduler::acl_queue_handler>(handle, acl_queue_handler));
51 if (fragments_to_send_.size() == 0) {
52 start_round_robin();
53 }
54 }
55
Unregister(uint16_t handle)56 void RoundRobinScheduler::Unregister(uint16_t handle) {
57 log::assert_that(
58 acl_queue_handlers_.count(handle) == 1,
59 "assert failed: acl_queue_handlers_.count(handle) == 1");
60 auto acl_queue_handler = acl_queue_handlers_.find(handle)->second;
61 // Reclaim outstanding packets
62 if (acl_queue_handler.connection_type_ == ConnectionType::CLASSIC) {
63 acl_packet_credits_ += acl_queue_handler.number_of_sent_packets_;
64 } else {
65 le_acl_packet_credits_ += acl_queue_handler.number_of_sent_packets_;
66 }
67 acl_queue_handler.number_of_sent_packets_ = 0;
68
69 if (acl_queue_handler.dequeue_is_registered_) {
70 acl_queue_handler.dequeue_is_registered_ = false;
71 acl_queue_handler.queue_->GetDownEnd()->UnregisterDequeue();
72 }
73 acl_queue_handlers_.erase(handle);
74 starting_point_ = acl_queue_handlers_.begin();
75 }
76
SetLinkPriority(uint16_t handle,bool high_priority)77 void RoundRobinScheduler::SetLinkPriority(uint16_t handle, bool high_priority) {
78 auto acl_queue_handler = acl_queue_handlers_.find(handle);
79 if (acl_queue_handler == acl_queue_handlers_.end()) {
80 log::warn("handle {} is invalid", handle);
81 return;
82 }
83 acl_queue_handler->second.high_priority_ = high_priority;
84 }
85
GetCredits()86 uint16_t RoundRobinScheduler::GetCredits() {
87 return acl_packet_credits_;
88 }
89
GetLeCredits()90 uint16_t RoundRobinScheduler::GetLeCredits() {
91 return le_acl_packet_credits_;
92 }
93
start_round_robin()94 void RoundRobinScheduler::start_round_robin() {
95 if (acl_packet_credits_ == 0 && le_acl_packet_credits_ == 0) {
96 return;
97 }
98 if (!fragments_to_send_.empty()) {
99 auto connection_type = fragments_to_send_.front().first;
100 bool classic_buffer_full = acl_packet_credits_ == 0 && connection_type == ConnectionType::CLASSIC;
101 bool le_buffer_full = le_acl_packet_credits_ == 0 && connection_type == ConnectionType::LE;
102 if (classic_buffer_full || le_buffer_full) {
103 log::warn("Buffer of connection_type {} is full", connection_type);
104 return;
105 }
106 send_next_fragment();
107 return;
108 }
109 if (acl_queue_handlers_.empty()) {
110 log::info("No any acl connection");
111 return;
112 }
113
114 if (acl_queue_handlers_.size() == 1 || starting_point_ == acl_queue_handlers_.end()) {
115 starting_point_ = acl_queue_handlers_.begin();
116 }
117 size_t count = acl_queue_handlers_.size();
118
119 for (auto acl_queue_handler = starting_point_; count > 0; count--) {
120 // Prevent registration when credits is zero
121 bool classic_buffer_full =
122 acl_packet_credits_ == 0 && acl_queue_handler->second.connection_type_ == ConnectionType::CLASSIC;
123 bool le_buffer_full =
124 le_acl_packet_credits_ == 0 && acl_queue_handler->second.connection_type_ == ConnectionType::LE;
125 if (!acl_queue_handler->second.dequeue_is_registered_ && !classic_buffer_full && !le_buffer_full) {
126 acl_queue_handler->second.dequeue_is_registered_ = true;
127 uint16_t acl_handle = acl_queue_handler->first;
128 acl_queue_handler->second.queue_->GetDownEnd()->RegisterDequeue(
129 handler_, common::Bind(&RoundRobinScheduler::buffer_packet, common::Unretained(this), acl_handle));
130 }
131 acl_queue_handler = std::next(acl_queue_handler);
132 if (acl_queue_handler == acl_queue_handlers_.end()) {
133 acl_queue_handler = acl_queue_handlers_.begin();
134 }
135 }
136
137 starting_point_ = std::next(starting_point_);
138 }
139
buffer_packet(uint16_t acl_handle)140 void RoundRobinScheduler::buffer_packet(uint16_t acl_handle) {
141 BroadcastFlag broadcast_flag = BroadcastFlag::POINT_TO_POINT;
142 auto acl_queue_handler = acl_queue_handlers_.find(acl_handle);
143 if( acl_queue_handler == acl_queue_handlers_.end()) {
144 log::error("Ignore since ACL connection vanished with handle: 0x{:X}", acl_handle);
145 return;
146 }
147
148 // Wrap packet and enqueue it
149 uint16_t handle = acl_queue_handler->first;
150 auto packet = acl_queue_handler->second.queue_->GetDownEnd()->TryDequeue();
151 log::assert_that(packet != nullptr, "assert failed: packet != nullptr");
152
153 ConnectionType connection_type = acl_queue_handler->second.connection_type_;
154 size_t mtu = connection_type == ConnectionType::CLASSIC ? hci_mtu_ : le_hci_mtu_;
155 PacketBoundaryFlag packet_boundary_flag = (packet->IsFlushable())
156 ? PacketBoundaryFlag::FIRST_AUTOMATICALLY_FLUSHABLE
157 : PacketBoundaryFlag::FIRST_NON_AUTOMATICALLY_FLUSHABLE;
158
159 int acl_priority = acl_queue_handler->second.high_priority_ ? 1 : 0;
160 if (packet->size() <= mtu) {
161 fragments_to_send_.push(
162 std::make_pair(
163 connection_type, AclBuilder::Create(handle, packet_boundary_flag, broadcast_flag, std::move(packet))),
164 acl_priority);
165 } else {
166 auto fragments = AclFragmenter(mtu, std::move(packet)).GetFragments();
167 for (size_t i = 0; i < fragments.size(); i++) {
168 fragments_to_send_.push(
169 std::make_pair(
170 connection_type,
171 AclBuilder::Create(handle, packet_boundary_flag, broadcast_flag, std::move(fragments[i]))),
172 acl_priority);
173 packet_boundary_flag = PacketBoundaryFlag::CONTINUING_FRAGMENT;
174 }
175 }
176 log::assert_that(fragments_to_send_.size() > 0, "assert failed: fragments_to_send_.size() > 0");
177 unregister_all_connections();
178
179 acl_queue_handler->second.number_of_sent_packets_ += fragments_to_send_.size();
180 send_next_fragment();
181 }
182
unregister_all_connections()183 void RoundRobinScheduler::unregister_all_connections() {
184 for (auto acl_queue_handler = acl_queue_handlers_.begin(); acl_queue_handler != acl_queue_handlers_.end();
185 acl_queue_handler = std::next(acl_queue_handler)) {
186 if (acl_queue_handler->second.dequeue_is_registered_) {
187 acl_queue_handler->second.dequeue_is_registered_ = false;
188 acl_queue_handler->second.queue_->GetDownEnd()->UnregisterDequeue();
189 }
190 }
191 }
192
send_next_fragment()193 void RoundRobinScheduler::send_next_fragment() {
194 if (!enqueue_registered_.exchange(true)) {
195 hci_queue_end_->RegisterEnqueue(
196 handler_, common::Bind(&RoundRobinScheduler::handle_enqueue_next_fragment, common::Unretained(this)));
197 }
198 }
199
200 // Invoked from some external Queue Reactable context 1
handle_enqueue_next_fragment()201 std::unique_ptr<AclBuilder> RoundRobinScheduler::handle_enqueue_next_fragment() {
202 ConnectionType connection_type = fragments_to_send_.front().first;
203 if (connection_type == ConnectionType::CLASSIC) {
204 log::assert_that(acl_packet_credits_ > 0, "assert failed: acl_packet_credits_ > 0");
205 acl_packet_credits_ -= 1;
206 } else {
207 log::assert_that(le_acl_packet_credits_ > 0, "assert failed: le_acl_packet_credits_ > 0");
208 le_acl_packet_credits_ -= 1;
209 }
210
211 auto raw_pointer = fragments_to_send_.front().second.release();
212 fragments_to_send_.pop();
213 if (fragments_to_send_.empty()) {
214 if (enqueue_registered_.exchange(false)) {
215 hci_queue_end_->UnregisterEnqueue();
216 }
217 handler_->Post(common::BindOnce(&RoundRobinScheduler::start_round_robin, common::Unretained(this)));
218 } else {
219 ConnectionType next_connection_type = fragments_to_send_.front().first;
220 bool classic_buffer_full = next_connection_type == ConnectionType::CLASSIC && acl_packet_credits_ == 0;
221 bool le_buffer_full = next_connection_type == ConnectionType::LE && le_acl_packet_credits_ == 0;
222 if ((classic_buffer_full || le_buffer_full) && enqueue_registered_.exchange(false)) {
223 hci_queue_end_->UnregisterEnqueue();
224 }
225 }
226 return std::unique_ptr<AclBuilder>(raw_pointer);
227 }
228
incoming_acl_credits(uint16_t handle,uint16_t credits)229 void RoundRobinScheduler::incoming_acl_credits(uint16_t handle, uint16_t credits) {
230 auto acl_queue_handler = acl_queue_handlers_.find(handle);
231 if (acl_queue_handler == acl_queue_handlers_.end()) {
232 return;
233 }
234
235 if (acl_queue_handler->second.number_of_sent_packets_ >= credits) {
236 acl_queue_handler->second.number_of_sent_packets_ -= credits;
237 } else {
238 log::warn("receive more credits than we sent");
239 acl_queue_handler->second.number_of_sent_packets_ = 0;
240 }
241
242 bool credit_was_zero = false;
243 if (acl_queue_handler->second.connection_type_ == ConnectionType::CLASSIC) {
244 if (acl_packet_credits_ == 0) {
245 credit_was_zero = true;
246 }
247 acl_packet_credits_ += credits;
248 if (acl_packet_credits_ > max_acl_packet_credits_) {
249 acl_packet_credits_ = max_acl_packet_credits_;
250 log::warn("acl packet credits overflow due to receive {} credits", credits);
251 }
252 } else {
253 if (le_acl_packet_credits_ == 0) {
254 credit_was_zero = true;
255 }
256 le_acl_packet_credits_ += credits;
257 if (le_acl_packet_credits_ > le_max_acl_packet_credits_) {
258 le_acl_packet_credits_ = le_max_acl_packet_credits_;
259 log::warn("le acl packet credits overflow due to receive {} credits", credits);
260 }
261 }
262 if (credit_was_zero) {
263 start_round_robin();
264 }
265 }
266
267 } // namespace acl_manager
268 } // namespace hci
269 } // namespace bluetooth
270