From 2bef92b59194c6474ebb5d2cd137583946e2b7e8 Mon Sep 17 00:00:00 2001 From: Chienyuan Date: Thu, 8 Apr 2021 15:37:19 +0800 Subject: [PATCH] gd hci: Check credit before sending next fragment Tag: #gd-refactor Bug: 180870443 Test: gd/cert/run BYPASS_LONG_LINES_REASON: Bluetooth likes 120 lines Change-Id: Ifd2af34886a0cf40d5ca3f4fdd4869089276d919 --- gd/hci/acl_manager/round_robin_scheduler.cc | 16 +++++++++- gd/hci/acl_manager/round_robin_scheduler_test.cc | 40 ++++++++++++++++++++++++ 2 files changed, 55 insertions(+), 1 deletion(-) diff --git a/gd/hci/acl_manager/round_robin_scheduler.cc b/gd/hci/acl_manager/round_robin_scheduler.cc index 6a469b01e..4790708ba 100644 --- a/gd/hci/acl_manager/round_robin_scheduler.cc +++ b/gd/hci/acl_manager/round_robin_scheduler.cc @@ -89,6 +89,13 @@ void RoundRobinScheduler::start_round_robin() { return; } if (!fragments_to_send_.empty()) { + auto connection_type = fragments_to_send_.front().first; + bool classic_buffer_full = acl_packet_credits_ == 0 && connection_type == ConnectionType::CLASSIC; + bool le_buffer_full = le_acl_packet_credits_ == 0 && connection_type == ConnectionType::LE; + if (classic_buffer_full || le_buffer_full) { + LOG_WARN("Buffer of connection_type %d is full", connection_type); + return; + } send_next_fragment(); return; } @@ -217,20 +224,27 @@ void RoundRobinScheduler::incoming_acl_credits(uint16_t handle, uint16_t credits acl_queue_handler->second.number_of_sent_packets_ = 0; } + bool credit_was_zero = false; if (acl_queue_handler->second.connection_type_ == ConnectionType::CLASSIC) { + if (acl_packet_credits_ == 0) { + credit_was_zero = true; + } acl_packet_credits_ += credits; if (acl_packet_credits_ > max_acl_packet_credits_) { acl_packet_credits_ = max_acl_packet_credits_; LOG_WARN("acl packet credits overflow due to receive %hx credits", credits); } } else { + if (le_acl_packet_credits_ == 0) { + credit_was_zero = true; + } le_acl_packet_credits_ += credits; if (le_acl_packet_credits_ > le_max_acl_packet_credits_) { le_acl_packet_credits_ = le_max_acl_packet_credits_; LOG_WARN("le acl packet credits overflow due to receive %hx credits", credits); } } - if (acl_packet_credits_ == credits || le_acl_packet_credits_ == credits) { + if (credit_was_zero) { start_round_robin(); } } diff --git a/gd/hci/acl_manager/round_robin_scheduler_test.cc b/gd/hci/acl_manager/round_robin_scheduler_test.cc index 03bcf9611..9d43c0f6f 100644 --- a/gd/hci/acl_manager/round_robin_scheduler_test.cc +++ b/gd/hci/acl_manager/round_robin_scheduler_test.cc @@ -370,6 +370,46 @@ TEST_F(RoundRobinSchedulerTest, send_fragments_without_interval) { round_robin_scheduler_->Unregister(le_handle); } +TEST_F(RoundRobinSchedulerTest, receive_le_credit_when_next_fragment_is_classic) { + uint16_t handle = 0x01; + uint16_t le_handle = 0x02; + auto connection_queue = std::make_shared(20); + auto le_connection_queue = std::make_shared(20); + + round_robin_scheduler_->Register(RoundRobinScheduler::ConnectionType::CLASSIC, handle, connection_queue); + round_robin_scheduler_->Register(RoundRobinScheduler::ConnectionType::LE, le_handle, le_connection_queue); + + SetPacketFuture(controller_->le_max_acl_packet_credits_ + controller_->max_acl_packet_credits_); + AclConnection::QueueUpEnd* queue_up_end = connection_queue->GetUpEnd(); + AclConnection::QueueUpEnd* le_queue_up_end = le_connection_queue->GetUpEnd(); + std::vector huge_packet(2000); + std::vector packet = {0x01, 0x02, 0x03}; + std::vector le_packet = {0x04, 0x05, 0x06}; + + // Make le_acl_packet_credits_ = 0; + for (uint16_t i = 0; i < controller_->le_max_acl_packet_credits_; i++) { + EnqueueAclUpEnd(le_queue_up_end, le_packet); + } + + // Make acl_packet_credits_ = 0 and remain 1 acl fragment in fragments_to_send_ + for (uint16_t i = 0; i < controller_->max_acl_packet_credits_ - 1; i++) { + EnqueueAclUpEnd(queue_up_end, packet); + } + EnqueueAclUpEnd(queue_up_end, huge_packet); + + packet_future_->wait(); + + // Trigger start_round_robin + controller_->SendCompletedAclPacketsCallback(0x02, 1); + std::this_thread::sleep_for(std::chrono::milliseconds(20)); + + ASSERT_EQ(round_robin_scheduler_->GetCredits(), 0); + ASSERT_EQ(round_robin_scheduler_->GetLeCredits(), 1); + + round_robin_scheduler_->Unregister(handle); + round_robin_scheduler_->Unregister(le_handle); +} + } // namespace acl_manager } // namespace hci } // namespace bluetooth -- 2.11.0