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<AclPacketBuilder,AclPacketView> * hci_queue_end)24 RoundRobinScheduler::RoundRobinScheduler(os::Handler* handler, Controller* controller,
25 common::BidiQueueEnd<AclPacketBuilder, AclPacketView>* hci_queue_end)
26 : handler_(handler), controller_(controller), hci_queue_end_(hci_queue_end) {
27 max_acl_packet_credits_ = controller_->GetControllerNumAclPacketBuffers();
28 acl_packet_credits_ = max_acl_packet_credits_;
29 hci_mtu_ = controller_->GetControllerAclPacketLength();
30 LeBufferSize le_buffer_size = controller_->GetControllerLeBufferSize();
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 acl_queue_handler acl_queue_handler = {connection_type, std::move(queue), false, 0};
45 acl_queue_handlers_.insert(std::pair<uint16_t, RoundRobinScheduler::acl_queue_handler>(handle, acl_queue_handler));
46 if (fragments_to_send_.size() == 0) {
47 start_round_robin();
48 }
49 }
50
Unregister(uint16_t handle)51 void RoundRobinScheduler::Unregister(uint16_t handle) {
52 ASSERT(acl_queue_handlers_.count(handle) == 1);
53 auto acl_queue_handler = acl_queue_handlers_.find(handle)->second;
54 // Reclaim outstanding packets
55 if (acl_queue_handler.connection_type_ == ConnectionType::CLASSIC) {
56 acl_packet_credits_ += acl_queue_handler.number_of_sent_packets_;
57 } else {
58 le_acl_packet_credits_ += acl_queue_handler.number_of_sent_packets_;
59 }
60 acl_queue_handler.number_of_sent_packets_ = 0;
61
62 if (acl_queue_handler.dequeue_is_registered_) {
63 acl_queue_handler.dequeue_is_registered_ = false;
64 acl_queue_handler.queue_->GetDownEnd()->UnregisterDequeue();
65 }
66 acl_queue_handlers_.erase(handle);
67 starting_point_ = acl_queue_handlers_.begin();
68 }
69
GetCredits()70 uint16_t RoundRobinScheduler::GetCredits() {
71 return acl_packet_credits_;
72 }
73
GetLeCredits()74 uint16_t RoundRobinScheduler::GetLeCredits() {
75 return le_acl_packet_credits_;
76 }
77
start_round_robin()78 void RoundRobinScheduler::start_round_robin() {
79 if (acl_packet_credits_ == 0 && le_acl_packet_credits_ == 0) {
80 return;
81 }
82 if (!fragments_to_send_.empty()) {
83 send_next_fragment();
84 return;
85 }
86
87 if (acl_queue_handlers_.size() == 1 || starting_point_ == acl_queue_handlers_.end()) {
88 starting_point_ = acl_queue_handlers_.begin();
89 }
90 size_t count = acl_queue_handlers_.size();
91
92 for (auto acl_queue_handler = starting_point_; count > 0; count--) {
93 // Prevent registration when credits is zero
94 bool classic_buffer_full =
95 acl_packet_credits_ == 0 && acl_queue_handler->second.connection_type_ == ConnectionType::CLASSIC;
96 bool le_buffer_full =
97 le_acl_packet_credits_ == 0 && acl_queue_handler->second.connection_type_ == ConnectionType::LE;
98 if (!acl_queue_handler->second.dequeue_is_registered_ && !classic_buffer_full && !le_buffer_full) {
99 acl_queue_handler->second.dequeue_is_registered_ = true;
100 acl_queue_handler->second.queue_->GetDownEnd()->RegisterDequeue(
101 handler_, common::Bind(&RoundRobinScheduler::buffer_packet, common::Unretained(this), acl_queue_handler));
102 }
103 acl_queue_handler = std::next(acl_queue_handler);
104 if (acl_queue_handler == acl_queue_handlers_.end()) {
105 acl_queue_handler = acl_queue_handlers_.begin();
106 }
107 }
108
109 starting_point_ = std::next(starting_point_);
110 }
111
buffer_packet(std::map<uint16_t,acl_queue_handler>::iterator acl_queue_handler)112 void RoundRobinScheduler::buffer_packet(std::map<uint16_t, acl_queue_handler>::iterator acl_queue_handler) {
113 BroadcastFlag broadcast_flag = BroadcastFlag::POINT_TO_POINT;
114 // Wrap packet and enqueue it
115 uint16_t handle = acl_queue_handler->first;
116 auto packet = acl_queue_handler->second.queue_->GetDownEnd()->TryDequeue();
117 ASSERT(packet != nullptr);
118
119 ConnectionType connection_type = acl_queue_handler->second.connection_type_;
120 size_t mtu = connection_type == ConnectionType::CLASSIC ? hci_mtu_ : le_hci_mtu_;
121 PacketBoundaryFlag packet_boundary_flag =
122 (connection_type == ConnectionType::CLASSIC ? PacketBoundaryFlag::FIRST_AUTOMATICALLY_FLUSHABLE
123 : PacketBoundaryFlag::FIRST_NON_AUTOMATICALLY_FLUSHABLE);
124 if (packet->size() <= mtu) {
125 fragments_to_send_.push(std::make_pair(
126 connection_type, AclPacketBuilder::Create(handle, packet_boundary_flag, broadcast_flag, std::move(packet))));
127 } else {
128 auto fragments = AclFragmenter(mtu, std::move(packet)).GetFragments();
129 for (size_t i = 0; i < fragments.size(); i++) {
130 fragments_to_send_.push(std::make_pair(
131 connection_type,
132 AclPacketBuilder::Create(handle, packet_boundary_flag, broadcast_flag, std::move(fragments[i]))));
133 packet_boundary_flag = PacketBoundaryFlag::CONTINUING_FRAGMENT;
134 }
135 }
136 ASSERT(fragments_to_send_.size() > 0);
137 unregister_all_connections();
138
139 acl_queue_handler->second.number_of_sent_packets_ += fragments_to_send_.size();
140 send_next_fragment();
141 }
142
unregister_all_connections()143 void RoundRobinScheduler::unregister_all_connections() {
144 for (auto acl_queue_handler = acl_queue_handlers_.begin(); acl_queue_handler != acl_queue_handlers_.end();
145 acl_queue_handler = std::next(acl_queue_handler)) {
146 if (acl_queue_handler->second.dequeue_is_registered_) {
147 acl_queue_handler->second.dequeue_is_registered_ = false;
148 acl_queue_handler->second.queue_->GetDownEnd()->UnregisterDequeue();
149 }
150 }
151 }
152
send_next_fragment()153 void RoundRobinScheduler::send_next_fragment() {
154 if (!enqueue_registered_.exchange(true)) {
155 hci_queue_end_->RegisterEnqueue(
156 handler_, common::Bind(&RoundRobinScheduler::handle_enqueue_next_fragment, common::Unretained(this)));
157 }
158 }
159
160 // Invoked from some external Queue Reactable context 1
handle_enqueue_next_fragment()161 std::unique_ptr<AclPacketBuilder> RoundRobinScheduler::handle_enqueue_next_fragment() {
162 ConnectionType connection_type = fragments_to_send_.front().first;
163 if (connection_type == ConnectionType::CLASSIC) {
164 ASSERT(acl_packet_credits_ > 0);
165 acl_packet_credits_ -= 1;
166 } else {
167 ASSERT(le_acl_packet_credits_ > 0);
168 le_acl_packet_credits_ -= 1;
169 }
170
171 auto raw_pointer = fragments_to_send_.front().second.release();
172 fragments_to_send_.pop();
173 if (fragments_to_send_.empty()) {
174 if (enqueue_registered_.exchange(false)) {
175 hci_queue_end_->UnregisterEnqueue();
176 }
177 handler_->Post(common::BindOnce(&RoundRobinScheduler::start_round_robin, common::Unretained(this)));
178 } else {
179 ConnectionType next_connection_type = fragments_to_send_.front().first;
180 bool classic_buffer_full = next_connection_type == ConnectionType::CLASSIC && acl_packet_credits_ == 0;
181 bool le_buffer_full = next_connection_type == ConnectionType::LE && le_acl_packet_credits_ == 0;
182 if ((classic_buffer_full || le_buffer_full) && enqueue_registered_.exchange(false)) {
183 hci_queue_end_->UnregisterEnqueue();
184 }
185 }
186 return std::unique_ptr<AclPacketBuilder>(raw_pointer);
187 }
188
incoming_acl_credits(uint16_t handle,uint16_t credits)189 void RoundRobinScheduler::incoming_acl_credits(uint16_t handle, uint16_t credits) {
190 auto acl_queue_handler = acl_queue_handlers_.find(handle);
191 if (acl_queue_handler == acl_queue_handlers_.end()) {
192 LOG_INFO("Dropping %hx received credits to unknown connection 0x%0hx", credits, handle);
193 return;
194 }
195 acl_queue_handler->second.number_of_sent_packets_ -= credits;
196 if (acl_queue_handler->second.connection_type_ == ConnectionType::CLASSIC) {
197 acl_packet_credits_ += credits;
198 } else {
199 le_acl_packet_credits_ += credits;
200 }
201 ASSERT(acl_packet_credits_ <= max_acl_packet_credits_);
202 ASSERT(le_acl_packet_credits_ <= le_max_acl_packet_credits_);
203 if (acl_packet_credits_ == credits || le_acl_packet_credits_ == credits) {
204 start_round_robin();
205 }
206 }
207
208 } // namespace acl_manager
209 } // namespace hci
210 } // namespace bluetooth
211