[nand] Use nand::UnownedOperation<>
Tested: paved astro
Change-Id: I920406359b4c63ed3f4a5a6b68fe6ffea2c35b39
diff --git a/system/dev/nand/nand/nand.cpp b/system/dev/nand/nand/nand.cpp
index c98aa02..0c18bd1 100644
--- a/system/dev/nand/nand/nand.cpp
+++ b/system/dev/nand/nand/nand.cpp
@@ -172,24 +172,23 @@
return status;
}
-void NandDevice::DoIo(Transaction* txn) {
+void NandDevice::DoIo(Transaction txn) {
zx_status_t status = ZX_OK;
- ZX_DEBUG_ASSERT(txn != nullptr);
- switch (txn->op.command) {
+ switch (txn.operation()->command) {
case NAND_OP_READ:
- status = ReadOp(&txn->op);
+ status = ReadOp(txn.operation());
break;
case NAND_OP_WRITE:
- status = WriteOp(&txn->op);
+ status = WriteOp(txn.operation());
break;
case NAND_OP_ERASE:
- status = EraseOp(&txn->op);
+ status = EraseOp(txn.operation());
break;
default:
ZX_DEBUG_ASSERT(false); // Unexpected.
}
- txn->Complete(status);
+ txn.Complete(status);
}
// Initialization is complete by the time the thread starts.
@@ -199,17 +198,12 @@
for (;;) {
// Don't loop until txn_queue_ is empty to check for kNandShutdown
// between each io.
- {
- fbl::AutoLock al(&lock_);
- Transaction* txn = txn_queue_.pop_front();
- if (txn) {
- // Unlock if we execute the transaction.
- al.release();
- DoIo(txn);
- } else {
- // Clear the "RECEIVED" flag under the lock.
- worker_event_.signal(kNandTxnReceived, 0);
- }
+ std::optional<Transaction> txn = txn_queue_.pop();
+ if (txn) {
+ DoIo(std::move(*txn));
+ } else {
+ // Clear the "RECEIVED" flag under the lock.
+ worker_event_.signal(kNandTxnReceived, 0);
}
zx_signals_t pending;
@@ -230,7 +224,7 @@
void NandDevice::NandQuery(fuchsia_hardware_nand_Info* info_out, size_t* nand_op_size_out) {
memcpy(info_out, &nand_info_, sizeof(*info_out));
- *nand_op_size_out = sizeof(Transaction);
+ *nand_op_size_out = Transaction::OperationSize(sizeof(nand_operation_t));
}
void NandDevice::NandQueue(nand_operation_t* op, nand_queue_callback completion_cb, void* cookie) {
@@ -240,19 +234,19 @@
return;
}
- Transaction* txn = Transaction::FromOp(op, completion_cb, cookie);
+ Transaction txn(op, completion_cb, cookie, sizeof(nand_operation_t));
- switch (txn->op.command) {
+ switch (op->command) {
case NAND_OP_READ:
case NAND_OP_WRITE: {
if (op->rw.offset_nand >= num_nand_pages_ || !op->rw.length ||
(num_nand_pages_ - op->rw.offset_nand) < op->rw.length) {
- txn->Complete(ZX_ERR_OUT_OF_RANGE);
+ txn.Complete(ZX_ERR_OUT_OF_RANGE);
return;
}
if (op->rw.data_vmo == ZX_HANDLE_INVALID &&
op->rw.oob_vmo == ZX_HANDLE_INVALID) {
- txn->Complete(ZX_ERR_BAD_HANDLE);
+ txn.Complete(ZX_ERR_BAD_HANDLE);
return;
}
break;
@@ -261,19 +255,18 @@
if (!op->erase.num_blocks ||
op->erase.first_block >= nand_info_.num_blocks ||
(op->erase.num_blocks > (nand_info_.num_blocks - op->erase.first_block))) {
- txn->Complete(ZX_ERR_OUT_OF_RANGE);
+ txn.Complete(ZX_ERR_OUT_OF_RANGE);
return;
}
break;
default:
- txn->Complete(ZX_ERR_NOT_SUPPORTED);
+ txn.Complete(ZX_ERR_NOT_SUPPORTED);
return;
}
- fbl::AutoLock al(&lock_);
// TODO: UPDATE STATS HERE.
- txn_queue_.push_back(txn);
+ txn_queue_.push(std::move(txn));
// Wake up the worker thread (while locked, so they don't accidentally
// clear the event).
worker_event_.signal(0, kNandTxnReceived);
@@ -294,16 +287,8 @@
worker_event_.signal(0, kNandShutdown);
thrd_join(worker_thread_, nullptr);
- {
- lock_.Acquire();
- // Error out all pending requests.
- for (auto& txn : txn_queue_) {
- lock_.Release();
- txn.Complete(ZX_ERR_BAD_STATE);
- lock_.Acquire();
- }
- lock_.Release();
- }
+ // Error out all pending requests.
+ txn_queue_.Release();
}
// static
diff --git a/system/dev/nand/nand/nand.h b/system/dev/nand/nand/nand.h
index 4d821c2..ff53d43 100644
--- a/system/dev/nand/nand/nand.h
+++ b/system/dev/nand/nand/nand.h
@@ -12,15 +12,16 @@
#include <ddktl/protocol/rawnand.h>
#include <fbl/intrusive_double_list.h>
#include <fbl/mutex.h>
+#include <lib/operation/nand.h>
#include <lib/fzl/vmo-mapper.h>
#include <lib/zx/event.h>
#include <zircon/thread_annotations.h>
#include <zircon/types.h>
-#include "transaction.h"
-
namespace nand {
+using Transaction = nand::UnownedOperation<>;
+
class NandDevice;
using DeviceType = ddk::Device<NandDevice, ddk::GetSizable, ddk::Unbindable>;
@@ -69,7 +70,7 @@
zx_status_t ReadOp(nand_operation_t* nand_op);
zx_status_t WriteOp(nand_operation_t* nand_op);
- void DoIo(Transaction* txn);
+ void DoIo(Transaction txn);
zx_status_t WorkerThread();
ddk::RawNandProtocolClient raw_nand_;
@@ -77,8 +78,7 @@
fuchsia_hardware_nand_Info nand_info_;
uint32_t num_nand_pages_;
- fbl::Mutex lock_;
- TransactionList txn_queue_ TA_GUARDED(lock_);
+ nand::UnownedOperationQueue<> txn_queue_;
thrd_t worker_thread_;
zx::event worker_event_;
diff --git a/system/dev/nand/nand/rules.mk b/system/dev/nand/nand/rules.mk
index 8ba2a1c..55a274e 100644
--- a/system/dev/nand/nand/rules.mk
+++ b/system/dev/nand/nand/rules.mk
@@ -15,6 +15,7 @@
$(LOCAL_DIR)/nand.cpp \
MODULE_STATIC_LIBS := \
+ system/dev/lib/operation \
system/ulib/ddk \
system/ulib/ddktl \
system/ulib/fbl \
@@ -58,6 +59,7 @@
MODULE_STATIC_LIBS := \
system/dev/lib/fake_ddk \
+ system/dev/lib/operation \
system/ulib/ddk \
system/ulib/ddktl \
system/ulib/fbl \
diff --git a/system/dev/nand/nand/transaction.h b/system/dev/nand/nand/transaction.h
deleted file mode 100644
index aae9f77..0000000
--- a/system/dev/nand/nand/transaction.h
+++ /dev/null
@@ -1,91 +0,0 @@
-// Copyright 2019 The Fuchsia Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#pragma once
-
-#include <memory>
-
-#include <stdlib.h>
-#include <stdio.h>
-
-#include <ddk/protocol/nand.h>
-#include <fbl/intrusive_double_list.h>
-#include <zircon/types.h>
-
-namespace nand {
-
-template <typename T>
-struct TransactionLinkedListTraits {
- using PtrTraits = fbl::internal::ContainerPtrTraits<T>;
- static fbl::DoublyLinkedListNodeState<T>& node_state(typename PtrTraits::RefType obj) {
- return obj.data.dll_node_state_;
- }
-};
-
-struct Transaction;
-
-// All data stored in a Transaction other than |nand_operation_t|.
-class TransactionData {
-private:
- TransactionData(nand_queue_callback completion_cb, void* cookie)
- : completion_cb_(completion_cb), cookie_(cookie) {}
-
- friend Transaction;
- friend TransactionLinkedListTraits<Transaction*>;
-
- nand_queue_callback completion_cb_;
- void* cookie_;
- fbl::DoublyLinkedListNodeState<Transaction*> dll_node_state_;
-};
-
-// A container for both a |nand_operation_t|, but also our arbitrary |TransactionData|.
-//
-// This structure is allocated by the upper level driver, and must be manually initialized
-// for incoming transactions.
-struct Transaction {
- // Returns a pointer to a Transaction given a nand_operation_t.
- //
- // To be used safely, the "nand_operation size" return value from |NandQuery| must
- // be at least sizeof(Transaction), requesting that enough space is allocated
- // alongside the |nand_operation_t| for the rest of |TransactionData| to fit.
- static Transaction* FromOp(nand_operation_t* op, nand_queue_callback completion_cb,
- void* cookie) {
- static_assert(offsetof(Transaction, op) == 0, "Cannot cast from nand op to transaction");
- auto txn = reinterpret_cast<Transaction*>(op);
-
- // Transaction was allocated by the upper level driver, but our TransactionData
- // was not actually constructed. Use placement new to ensure the
- // object is initialized, with a complementary explicit destructor of TransactionData
- // within |Complete|.
- new (&txn->data) TransactionData(completion_cb, cookie);
- return txn;
- }
-
- // Since |TransactionData| is destructed in-place in calls to |Complete|, ensure
- // the typical destructor of Transaction is never executed.
- ~Transaction() = delete;
-
- void Complete(zx_status_t status) {
- // Since completing a transaction may de-allocate the transaction, save our state
- // and execute the placment destructor of TransactionData before invoking the
- // completion callback.
- nand_queue_callback completion_cb = data.completion_cb_;
- void* cookie = data.cookie_;
-
- data.~TransactionData();
-
- // Transaction should not be referenced after invoking the completion callback.
- completion_cb(cookie, status, &op);
- }
-
- nand_operation_t op;
- TransactionData data;
-};
-
-static_assert(std::is_standard_layout<Transaction>::value,
- "Transaction must be standard layout to be convertible from a nand_operation_t");
-
-using TransactionList = fbl::DoublyLinkedList<Transaction*,
- TransactionLinkedListTraits<Transaction*>>;
-} // namespace nand