blob: b286c2ee0ecedac03c2fd70d645162d30db4dc44 [file] [log] [blame]
// Copyright 2018 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 <threads.h>
#include <ddk/driver.h>
#include <ddktl/device.h>
#include <ddktl/protocol/nand.h>
#include <ddktl/protocol/rawnand.h>
#include <fbl/condition_variable.h>
#include <fbl/intrusive_double_list.h>
#include <fbl/mutex.h>
#include <lib/fzl/vmo-mapper.h>
#include <lib/operation/nand.h>
#include <zircon/thread_annotations.h>
#include <zircon/types.h>
namespace nand {
using Transaction = nand::UnownedOperation<>;
class NandDevice;
using DeviceType = ddk::Device<NandDevice, ddk::GetSizable, ddk::Unbindable>;
class NandDevice : public DeviceType,
public ddk::NandProtocol<NandDevice, ddk::base_protocol> {
public:
explicit NandDevice(zx_device_t* parent)
: DeviceType(parent), raw_nand_(parent) {}
DISALLOW_COPY_ASSIGN_AND_MOVE(NandDevice);
~NandDevice();
static zx_status_t Create(void* ctx, zx_device_t* parent);
zx_status_t Bind();
zx_status_t Init();
// Device protocol implementation.
zx_off_t DdkGetSize() {
return device_get_size(parent());
}
void DdkUnbind() { DdkRemove(); }
void DdkRelease();
// Nand protocol implementation.
void NandQuery(fuchsia_hardware_nand_Info* info_out, size_t* nand_op_size_out);
void NandQueue(nand_operation_t* op, nand_queue_callback completion_cb, void* cookie);
zx_status_t NandGetFactoryBadBlockList(uint32_t* bad_blocks, size_t bad_block_len,
size_t* num_bad_blocks);
private:
// Maps the data and oob vmos from the specified |nand_op| into memory.
zx_status_t MapVmos(const nand_operation_t& nand_op, fzl::VmoMapper* data, uint8_t** vaddr_data,
fzl::VmoMapper* oob, uint8_t** vaddr_oob);
// Calls controller specific read function.
// data, oob: pointers to user oob/data buffers.
// nand_page : NAND page address to read.
// ecc_correct : Number of ecc corrected bitflips (< 0 indicates
// ecc could not correct all bitflips - caller needs to check that).
// retries : Retry logic may not be needed.
zx_status_t ReadPage(void* data, void* oob, uint32_t nand_page, uint32_t* corrected_bits,
size_t retries);
zx_status_t EraseOp(nand_operation_t* nand_op);
zx_status_t ReadOp(nand_operation_t* nand_op);
zx_status_t WriteOp(nand_operation_t* nand_op);
void DoIo(Transaction txn);
zx_status_t WorkerThread();
ddk::RawNandProtocolClient raw_nand_;
fuchsia_hardware_nand_Info nand_info_;
uint32_t num_nand_pages_;
thrd_t worker_thread_;
fbl::Mutex lock_;
nand::UnownedOperationQueue<> txn_queue_ TA_GUARDED(lock_);
fbl::ConditionVariable worker_event_ TA_GUARDED(lock_);
bool shutdown_ TA_GUARDED(lock_) = false;
};
} // namespace nand