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