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