* @brief 提交 Scatter-Gather 描述符链 * * 从空闲链表分配描述符,按顺序组装 readable(设备只读)和 * writable(设备可写) 缓冲区为描述符链,自动设置 NEXT 标志串联,并提交到 * Available Ring。 * * 描述符链顺序:[readable_0, ..., readable_N, writable_0, ..., writable_M] * - readable 部分:flags = kDescFNext(无 kDescFWrite) * - writable 部分:flags = kDescFNext | kDescFWrite * - 最后一个描述符清除 kDescFNext * * 调用者在调用此方法后仍需调用内存屏障 + Transport::Noti
| 458 | * @see 架构文档 §3 Scatter-Gather |
| 459 | */ |
| 460 | [[nodiscard]] auto SubmitChain(const IoVec* readable, size_t readable_count, |
| 461 | const IoVec* writable, size_t writable_count) |
| 462 | -> Expected<uint16_t> { |
| 463 | size_t total = readable_count + writable_count; |
| 464 | if (total == 0) { |
| 465 | return std::unexpected(Error{ErrorCode::kInvalidArgument}); |
| 466 | } |
| 467 | if (num_free_ < static_cast<uint16_t>(total)) { |
| 468 | return std::unexpected(Error{ErrorCode::kNoFreeDescriptors}); |
| 469 | } |
| 470 | |
| 471 | uint16_t head = free_head_; |
| 472 | uint16_t prev_idx = 0xFFFF; |
| 473 | |
| 474 | for (size_t i = 0; i < readable_count; ++i) { |
| 475 | uint16_t idx = free_head_; |
| 476 | free_head_ = desc_[free_head_].next; |
| 477 | --num_free_; |
| 478 | |
| 479 | desc_[idx].addr = readable[i].phys_addr; |
| 480 | desc_[idx].len = static_cast<uint32_t>(readable[i].len); |
| 481 | desc_[idx].flags = std::to_underlying(DescFlags::kDescFNext); |
| 482 | |
| 483 | if (prev_idx != 0xFFFF) { |
| 484 | desc_[prev_idx].next = idx; |
| 485 | } |
| 486 | prev_idx = idx; |
| 487 | } |
| 488 | |
| 489 | for (size_t i = 0; i < writable_count; ++i) { |
| 490 | uint16_t idx = free_head_; |
| 491 | free_head_ = desc_[free_head_].next; |
| 492 | --num_free_; |
| 493 | |
| 494 | desc_[idx].addr = writable[i].phys_addr; |
| 495 | desc_[idx].len = static_cast<uint32_t>(writable[i].len); |
| 496 | desc_[idx].flags = std::to_underlying(DescFlags::kDescFNext) | |
| 497 | std::to_underlying(DescFlags::kDescFWrite); |
| 498 | if (prev_idx != 0xFFFF) { |
| 499 | desc_[prev_idx].next = idx; |
| 500 | } |
| 501 | prev_idx = idx; |
| 502 | } |
| 503 | |
| 504 | desc_[prev_idx].flags = |
| 505 | desc_[prev_idx].flags & ~std::to_underlying(DescFlags::kDescFNext); |
| 506 | |
| 507 | // 写屏障:确保描述符写入在 Available Ring 更新之前对设备可见 |
| 508 | cpu_io::Wmb(); |
| 509 | |
| 510 | Submit(head); |
| 511 | |
| 512 | return head; |
| 513 | } |
| 514 | |
| 515 | /** |
| 516 | * @brief 释放整条描述符链 |
no test coverage detected