blob: bac1d8faddb46d93084a68a74b3bb98e45e40b36 [file] [log] [blame]
// 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.
#ifndef SRC_STORAGE_BLOCK_DRIVERS_AHCI_PORT_H_
#define SRC_STORAGE_BLOCK_DRIVERS_AHCI_PORT_H_
#include <threads.h>
#include <zircon/types.h>
#include <ddk/io-buffer.h>
#include <ddk/mmio-buffer.h>
#include <fbl/mutex.h>
#include "bus.h"
#include "sata.h"
namespace ahci {
// port is implemented by the controller
constexpr uint32_t kPortFlagImplemented = (1u << 0);
// a device is present on port
constexpr uint32_t kPortFlagPresent = (1u << 1);
// port is paused (no queued transactions will be processed)
// until pending transactions are done
constexpr uint32_t kPortFlagSyncPaused = (1u << 2);
// Command table for a port.
struct ahci_command_tab_t {
ahci_ct_t ct;
ahci_prd_t prd[AHCI_MAX_PRDS];
} __attribute__((aligned(128)));
// Memory for port command lists is laid out in the order described by this struct.
struct ahci_port_mem_t {
ahci_cl_t cl[AHCI_MAX_COMMANDS]; // 1024-byte aligned.
ahci_fis_t fis; // 256-byte aligned.
ahci_command_tab_t tab[AHCI_MAX_COMMANDS]; // 128-byte aligned.
};
static_assert(sizeof(ahci_port_mem_t) == 271616, "port memory layout size invalid");
class Controller;
class Port {
public:
Port();
~Port();
DISALLOW_COPY_ASSIGN_AND_MOVE(Port);
// Configure a port for use.
zx_status_t Configure(uint32_t num, Bus* bus, size_t reg_base, uint32_t capabilities);
uint32_t RegRead(size_t offset);
void RegWrite(size_t offset, uint32_t val);
zx_status_t Enable();
void Disable();
void Reset();
void SetDevInfo(const sata_devinfo_t* devinfo);
zx_status_t Queue(sata_txn_t* txn);
// Complete in-progress transactions.
// Returns true if there remain transactions in progress.
bool Complete();
// Process incoming transaction queue and run them.
// Returns true if transactions were added (are now in progress)
bool ProcessQueued();
// Returns true if a transaction was handled.
bool HandleIrq();
uint32_t num() { return num_; }
// Capabilities
// Returns true if controller supports Native Command Queuing.
bool HasCommandQueue() { return cap_ & AHCI_CAP_NCQ; }
// Returns maximum number of simultaneous commands on each port.
uint32_t MaxCommands() { return static_cast<uint32_t>((cap_ >> 8) & 0x1f); }
// These flag-access functions should require holding the port lock.
// In their current use, they frequently access them unlocked. This
// will be fixed and thread annotations will be added in future CLs.
bool is_implemented() { return flags_ & kPortFlagImplemented; }
bool is_present() { return flags_ & kPortFlagPresent; }
void set_present(bool present) {
present ? flags_ |= kPortFlagPresent : flags_ &= ~kPortFlagPresent;
}
bool is_valid() {
uint32_t valid_flags = kPortFlagImplemented | kPortFlagPresent;
return (flags_ & valid_flags) == valid_flags;
}
bool is_paused() { return (flags_ & kPortFlagSyncPaused); }
// Test functions
// Mark transaction as running without going through the Queue path.
// Does not modify bus registers.
void TestSetRunning(sata_txn_t* txn, uint32_t slot);
private:
bool SlotBusyLocked(uint32_t slot);
zx_status_t TxnBeginLocked(uint32_t slot, sata_txn_t* txn);
void TxnComplete(zx_status_t status);
uint32_t num_ = 0; // 0-based
// Pointer to controller's bus provider. Pointer is not owned.
Bus* bus_ = nullptr;
uint32_t cap_ = 0; // Copy of controller capabilities register.
fbl::Mutex lock_;
uint32_t flags_ = 0;
list_node_t txn_list_{};
uint32_t running_ = 0; // bitmask of running commands
uint32_t completed_ = 0; // bitmask of completed commands
sata_txn_t* sync_ = nullptr; // FLUSH command in flight
io_buffer_t buffer_{};
size_t reg_base_ = 0;
ahci_port_mem_t* mem_ = nullptr;
sata_devinfo_t devinfo_{};
sata_txn_t* commands_[AHCI_MAX_COMMANDS] = {}; // commands in flight
};
} // namespace ahci
#endif // SRC_STORAGE_BLOCK_DRIVERS_AHCI_PORT_H_