480 lines
11 KiB
C
480 lines
11 KiB
C
/*
|
|
* Copyright (c) 2022 Intel Corporation
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*
|
|
* Derived from FreeBSD original driver made by Jim Harris
|
|
* with contributions from Alexander Motin and Wojciech Macek
|
|
*/
|
|
|
|
#ifndef ZEPHYR_DRIVERS_DISK_NVME_NHME_H_
|
|
#define ZEPHYR_DRIVERS_DISK_NVME_NVME_H_
|
|
|
|
#include "nvme_helpers.h"
|
|
#include "nvme_cmd.h"
|
|
#include "nvme_namespace.h"
|
|
|
|
struct nvme_registers {
|
|
uint32_t cap_lo; /* controller capabilities */
|
|
uint32_t cap_hi;
|
|
uint32_t vs; /* version */
|
|
uint32_t intms; /* interrupt mask set */
|
|
uint32_t intmc; /* interrupt mask clear */
|
|
uint32_t cc; /* controller configuration */
|
|
uint32_t reserved1;
|
|
uint32_t csts; /* controller status */
|
|
uint32_t nssr; /* NVM Subsystem Reset */
|
|
uint32_t aqa; /* admin queue attributes */
|
|
uint64_t asq; /* admin submission queue base addr */
|
|
uint64_t acq; /* admin completion queue base addr */
|
|
uint32_t cmbloc; /* Controller Memory Buffer Location */
|
|
uint32_t cmbsz; /* Controller Memory Buffer Size */
|
|
uint32_t bpinfo; /* Boot Partition Information */
|
|
uint32_t bprsel; /* Boot Partition Read Select */
|
|
uint64_t bpmbl; /* Boot Partition Memory Buffer Location */
|
|
uint64_t cmbmsc; /* Controller Memory Buffer Memory Space Control */
|
|
uint32_t cmbsts; /* Controller Memory Buffer Status */
|
|
uint8_t reserved3[3492]; /* 5Ch - DFFh */
|
|
uint32_t pmrcap; /* Persistent Memory Capabilities */
|
|
uint32_t pmrctl; /* Persistent Memory Region Control */
|
|
uint32_t pmrsts; /* Persistent Memory Region Status */
|
|
uint32_t pmrebs; /* Persistent Memory Region Elasticity Buffer Size */
|
|
uint32_t pmrswtp; /* Persistent Memory Region Sustained Write Throughput */
|
|
uint32_t pmrmsc_lo; /* Persistent Memory Region Controller Memory Space Control */
|
|
uint32_t pmrmsc_hi;
|
|
uint8_t reserved4[484]; /* E1Ch - FFFh */
|
|
struct {
|
|
uint32_t sq_tdbl; /* submission queue tail doorbell */
|
|
uint32_t cq_hdbl; /* completion queue head doorbell */
|
|
} doorbell[1];
|
|
};
|
|
|
|
struct nvme_power_state {
|
|
/** Maximum Power */
|
|
uint16_t mp;
|
|
uint8_t ps_rsvd1;
|
|
|
|
/** Max Power Scale, Non-Operational State */
|
|
uint8_t mps_nops;
|
|
|
|
/** Entry Latency */
|
|
uint32_t enlat;
|
|
|
|
/** Exit Latency */
|
|
uint32_t exlat;
|
|
|
|
/** Relative Read Throughput */
|
|
uint8_t rrt;
|
|
|
|
/** Relative Read Latency */
|
|
uint8_t rrl;
|
|
|
|
/** Relative Write Throughput */
|
|
uint8_t rwt;
|
|
|
|
/** Relative Write Latency */
|
|
uint8_t rwl;
|
|
|
|
/** Idle Power */
|
|
uint16_t idlp;
|
|
|
|
/** Idle Power Scale */
|
|
uint8_t ips;
|
|
uint8_t ps_rsvd8;
|
|
|
|
/** Active Power */
|
|
uint16_t actp;
|
|
|
|
/** Active Power Workload, Active Power Scale */
|
|
uint8_t apw_aps;
|
|
|
|
uint8_t ps_rsvd10[9];
|
|
} __packed;
|
|
|
|
#define NVME_SERIAL_NUMBER_LENGTH 20
|
|
#define NVME_MODEL_NUMBER_LENGTH 40
|
|
#define NVME_FIRMWARE_REVISION_LENGTH 8
|
|
|
|
struct nvme_controller_data {
|
|
/* bytes 0-255: controller capabilities and features */
|
|
|
|
/** pci vendor id */
|
|
uint16_t vid;
|
|
|
|
/** pci subsystem vendor id */
|
|
uint16_t ssvid;
|
|
|
|
/** serial number */
|
|
uint8_t sn[NVME_SERIAL_NUMBER_LENGTH];
|
|
|
|
/** model number */
|
|
uint8_t mn[NVME_MODEL_NUMBER_LENGTH];
|
|
|
|
/** firmware revision */
|
|
uint8_t fr[NVME_FIRMWARE_REVISION_LENGTH];
|
|
|
|
/** recommended arbitration burst */
|
|
uint8_t rab;
|
|
|
|
/** ieee oui identifier */
|
|
uint8_t ieee[3];
|
|
|
|
/** multi-interface capabilities */
|
|
uint8_t mic;
|
|
|
|
/** maximum data transfer size */
|
|
uint8_t mdts;
|
|
|
|
/** Controller ID */
|
|
uint16_t ctrlr_id;
|
|
|
|
/** Version */
|
|
uint32_t ver;
|
|
|
|
/** RTD3 Resume Latency */
|
|
uint32_t rtd3r;
|
|
|
|
/** RTD3 Enter Latency */
|
|
uint32_t rtd3e;
|
|
|
|
/** Optional Asynchronous Events Supported */
|
|
uint32_t oaes; /* bitfield really */
|
|
|
|
/** Controller Attributes */
|
|
uint32_t ctratt; /* bitfield really */
|
|
|
|
/** Read Recovery Levels Supported */
|
|
uint16_t rrls;
|
|
|
|
uint8_t reserved1[9];
|
|
|
|
/** Controller Type */
|
|
uint8_t cntrltype;
|
|
|
|
/** FRU Globally Unique Identifier */
|
|
uint8_t fguid[16];
|
|
|
|
/** Command Retry Delay Time 1 */
|
|
uint16_t crdt1;
|
|
|
|
/** Command Retry Delay Time 2 */
|
|
uint16_t crdt2;
|
|
|
|
/** Command Retry Delay Time 3 */
|
|
uint16_t crdt3;
|
|
|
|
uint8_t reserved2[122];
|
|
|
|
/* bytes 256-511: admin command set attributes */
|
|
|
|
/** optional admin command support */
|
|
uint16_t oacs;
|
|
|
|
/** abort command limit */
|
|
uint8_t acl;
|
|
|
|
/** asynchronous event request limit */
|
|
uint8_t aerl;
|
|
|
|
/** firmware updates */
|
|
uint8_t frmw;
|
|
|
|
/** log page attributes */
|
|
uint8_t lpa;
|
|
|
|
/** error log page entries */
|
|
uint8_t elpe;
|
|
|
|
/** number of power states supported */
|
|
uint8_t npss;
|
|
|
|
/** admin vendor specific command configuration */
|
|
uint8_t avscc;
|
|
|
|
/** Autonomous Power State Transition Attributes */
|
|
uint8_t apsta;
|
|
|
|
/** Warning Composite Temperature Threshold */
|
|
uint16_t wctemp;
|
|
|
|
/** Critical Composite Temperature Threshold */
|
|
uint16_t cctemp;
|
|
|
|
/** Maximum Time for Firmware Activation */
|
|
uint16_t mtfa;
|
|
|
|
/** Host Memory Buffer Preferred Size */
|
|
uint32_t hmpre;
|
|
|
|
/** Host Memory Buffer Minimum Size */
|
|
uint32_t hmmin;
|
|
|
|
/** Name space capabilities */
|
|
struct {
|
|
/* if nsmgmt, report tnvmcap and unvmcap */
|
|
uint8_t tnvmcap[16];
|
|
uint8_t unvmcap[16];
|
|
} __packed untncap;
|
|
|
|
/** Replay Protected Memory Block Support */
|
|
uint32_t rpmbs; /* Really a bitfield */
|
|
|
|
/** Extended Device Self-test Time */
|
|
uint16_t edstt;
|
|
|
|
/** Device Self-test Options */
|
|
uint8_t dsto; /* Really a bitfield */
|
|
|
|
/** Firmware Update Granularity */
|
|
uint8_t fwug;
|
|
|
|
/** Keep Alive Support */
|
|
uint16_t kas;
|
|
|
|
/** Host Controlled Thermal Management Attributes */
|
|
uint16_t hctma; /* Really a bitfield */
|
|
|
|
/** Minimum Thermal Management Temperature */
|
|
uint16_t mntmt;
|
|
|
|
/** Maximum Thermal Management Temperature */
|
|
uint16_t mxtmt;
|
|
|
|
/** Sanitize Capabilities */
|
|
uint32_t sanicap; /* Really a bitfield */
|
|
|
|
/** Host Memory Buffer Minimum Descriptor Entry Size */
|
|
uint32_t hmminds;
|
|
|
|
/** Host Memory Maximum Descriptors Entries */
|
|
uint16_t hmmaxd;
|
|
|
|
/** NVM Set Identifier Maximum */
|
|
uint16_t nsetidmax;
|
|
|
|
/** Endurance Group Identifier Maximum */
|
|
uint16_t endgidmax;
|
|
|
|
/** ANA Transition Time */
|
|
uint8_t anatt;
|
|
|
|
/** Asymmetric Namespace Access Capabilities */
|
|
uint8_t anacap;
|
|
|
|
/** ANA Group Identifier Maximum */
|
|
uint32_t anagrpmax;
|
|
|
|
/** Number of ANA Group Identifiers */
|
|
uint32_t nanagrpid;
|
|
|
|
/** Persistent Event Log Size */
|
|
uint32_t pels;
|
|
|
|
uint8_t reserved3[156];
|
|
/* bytes 512-703: nvm command set attributes */
|
|
|
|
/** submission queue entry size */
|
|
uint8_t sqes;
|
|
|
|
/** completion queue entry size */
|
|
uint8_t cqes;
|
|
|
|
/** Maximum Outstanding Commands */
|
|
uint16_t maxcmd;
|
|
|
|
/** number of namespaces */
|
|
uint32_t nn;
|
|
|
|
/** optional nvm command support */
|
|
uint16_t oncs;
|
|
|
|
/** fused operation support */
|
|
uint16_t fuses;
|
|
|
|
/** format nvm attributes */
|
|
uint8_t fna;
|
|
|
|
/** volatile write cache */
|
|
uint8_t vwc;
|
|
|
|
/** Atomic Write Unit Normal */
|
|
uint16_t awun;
|
|
|
|
/** Atomic Write Unit Power Fail */
|
|
uint16_t awupf;
|
|
|
|
/** NVM Vendor Specific Command Configuration */
|
|
uint8_t nvscc;
|
|
|
|
/** Namespace Write Protection Capabilities */
|
|
uint8_t nwpc;
|
|
|
|
/** Atomic Compare & Write Unit */
|
|
uint16_t acwu;
|
|
uint16_t reserved6;
|
|
|
|
/** SGL Support */
|
|
uint32_t sgls;
|
|
|
|
/** Maximum Number of Allowed Namespaces */
|
|
uint32_t mnan;
|
|
|
|
/* bytes 540-767: Reserved */
|
|
uint8_t reserved7[224];
|
|
|
|
/** NVM Subsystem NVMe Qualified Name */
|
|
uint8_t subnqn[256];
|
|
|
|
/* bytes 1024-1791: Reserved */
|
|
uint8_t reserved8[768];
|
|
|
|
/* bytes 1792-2047: NVMe over Fabrics specification */
|
|
uint8_t reserved9[256];
|
|
|
|
/* bytes 2048-3071: power state descriptors */
|
|
struct nvme_power_state power_state[32];
|
|
|
|
/* bytes 3072-4095: vendor specific */
|
|
uint8_t vs[1024];
|
|
} __packed __aligned(4);
|
|
|
|
static inline
|
|
void nvme_controller_data_swapbytes(struct nvme_controller_data *s)
|
|
{
|
|
#if _BYTE_ORDER != _LITTLE_ENDIAN
|
|
s->vid = sys_le16_to_cpu(s->vid);
|
|
s->ssvid = sys_le16_to_cpu(s->ssvid);
|
|
s->ctrlr_id = sys_le16_to_cpu(s->ctrlr_id);
|
|
s->ver = sys_le32_to_cpu(s->ver);
|
|
s->rtd3r = sys_le32_to_cpu(s->rtd3r);
|
|
s->rtd3e = sys_le32_to_cpu(s->rtd3e);
|
|
s->oaes = sys_le32_to_cpu(s->oaes);
|
|
s->ctratt = sys_le32_to_cpu(s->ctratt);
|
|
s->rrls = sys_le16_to_cpu(s->rrls);
|
|
s->crdt1 = sys_le16_to_cpu(s->crdt1);
|
|
s->crdt2 = sys_le16_to_cpu(s->crdt2);
|
|
s->crdt3 = sys_le16_to_cpu(s->crdt3);
|
|
s->oacs = sys_le16_to_cpu(s->oacs);
|
|
s->wctemp = sys_le16_to_cpu(s->wctemp);
|
|
s->cctemp = sys_le16_to_cpu(s->cctemp);
|
|
s->mtfa = sys_le16_to_cpu(s->mtfa);
|
|
s->hmpre = sys_le32_to_cpu(s->hmpre);
|
|
s->hmmin = sys_le32_to_cpu(s->hmmin);
|
|
s->rpmbs = sys_le32_to_cpu(s->rpmbs);
|
|
s->edstt = sys_le16_to_cpu(s->edstt);
|
|
s->kas = sys_le16_to_cpu(s->kas);
|
|
s->hctma = sys_le16_to_cpu(s->hctma);
|
|
s->mntmt = sys_le16_to_cpu(s->mntmt);
|
|
s->mxtmt = sys_le16_to_cpu(s->mxtmt);
|
|
s->sanicap = sys_le32_to_cpu(s->sanicap);
|
|
s->hmminds = sys_le32_to_cpu(s->hmminds);
|
|
s->hmmaxd = sys_le16_to_cpu(s->hmmaxd);
|
|
s->nsetidmax = sys_le16_to_cpu(s->nsetidmax);
|
|
s->endgidmax = sys_le16_to_cpu(s->endgidmax);
|
|
s->anagrpmax = sys_le32_to_cpu(s->anagrpmax);
|
|
s->nanagrpid = sys_le32_to_cpu(s->nanagrpid);
|
|
s->pels = sys_le32_to_cpu(s->pels);
|
|
s->maxcmd = sys_le16_to_cpu(s->maxcmd);
|
|
s->nn = sys_le32_to_cpu(s->nn);
|
|
s->oncs = sys_le16_to_cpu(s->oncs);
|
|
s->fuses = sys_le16_to_cpu(s->fuses);
|
|
s->awun = sys_le16_to_cpu(s->awun);
|
|
s->awupf = sys_le16_to_cpu(s->awupf);
|
|
s->acwu = sys_le16_to_cpu(s->acwu);
|
|
s->sgls = sys_le32_to_cpu(s->sgls);
|
|
s->mnan = sys_le32_to_cpu(s->mnan);
|
|
#else
|
|
ARG_UNUSED(s);
|
|
#endif
|
|
}
|
|
|
|
#include <zephyr/device.h>
|
|
#include <zephyr/drivers/pcie/pcie.h>
|
|
#include <zephyr/drivers/pcie/msi.h>
|
|
|
|
#define NVME_PCIE_BAR_IDX 0
|
|
|
|
#define NVME_REQUEST_AMOUNT (CONFIG_NVME_ADMIN_ENTRIES + \
|
|
CONFIG_NVME_IO_ENTRIES)
|
|
|
|
/* admin queue + io queue(s) */
|
|
#define NVME_PCIE_MSIX_VECTORS 1 + CONFIG_NVME_IO_QUEUES
|
|
|
|
#define NVME_QUEUE_ALLOCATE(name, n_entries) \
|
|
static struct nvme_command cmd_##name[n_entries] __aligned(0x1000); \
|
|
static struct nvme_completion cpl_##name[n_entries] __aligned(0x1000); \
|
|
\
|
|
static struct nvme_cmd_qpair name = { \
|
|
.num_entries = n_entries, \
|
|
.cmd = cmd_##name, \
|
|
.cpl = cpl_##name, \
|
|
}
|
|
|
|
#define NVME_ADMINQ_ALLOCATE(n, n_entries) \
|
|
NVME_QUEUE_ALLOCATE(admin_##n, n_entries)
|
|
#define NVME_IOQ_ALLOCATE(n, n_entries) \
|
|
NVME_QUEUE_ALLOCATE(io_##n, n_entries)
|
|
|
|
struct nvme_controller_config {
|
|
struct pcie_dev *pcie;
|
|
};
|
|
|
|
struct nvme_controller {
|
|
DEVICE_MMIO_RAM;
|
|
|
|
const struct device *dev;
|
|
|
|
struct k_mutex lock;
|
|
|
|
uint32_t id;
|
|
|
|
msi_vector_t vectors[NVME_PCIE_MSIX_VECTORS];
|
|
|
|
struct nvme_controller_data cdata;
|
|
|
|
uint32_t num_io_queues;
|
|
struct nvme_cmd_qpair *adminq;
|
|
struct nvme_cmd_qpair *ioq;
|
|
|
|
uint32_t ready_timeout_in_ms;
|
|
|
|
/** LO and HI capacity mask */
|
|
uint32_t cap_lo;
|
|
uint32_t cap_hi;
|
|
|
|
/** Page size and log2(page_size) - 12 that we're currently using */
|
|
uint32_t page_size;
|
|
uint32_t mps;
|
|
|
|
/** doorbell stride */
|
|
uint32_t dstrd;
|
|
|
|
/** maximum i/o size in bytes */
|
|
uint32_t max_xfer_size;
|
|
|
|
struct nvme_namespace ns[CONFIG_NVME_MAX_NAMESPACES];
|
|
};
|
|
|
|
static inline
|
|
bool nvme_controller_has_dataset_mgmt(struct nvme_controller *ctrlr)
|
|
{
|
|
/* Assumes cd was byte swapped by nvme_controller_data_swapbytes() */
|
|
return ((ctrlr->cdata.oncs >> NVME_CTRLR_DATA_ONCS_DSM_SHIFT) &
|
|
NVME_CTRLR_DATA_ONCS_DSM_MASK);
|
|
}
|
|
|
|
static inline void nvme_lock(const struct device *dev)
|
|
{
|
|
struct nvme_controller *nvme_ctrlr = dev->data;
|
|
|
|
k_mutex_lock(&nvme_ctrlr->lock, K_FOREVER);
|
|
}
|
|
|
|
static inline void nvme_unlock(const struct device *dev)
|
|
{
|
|
struct nvme_controller *nvme_ctrlr = dev->data;
|
|
|
|
k_mutex_unlock(&nvme_ctrlr->lock);
|
|
}
|
|
|
|
#endif /* ZEPHYR_DRIVERS_DISK_NVME_NHME_H_ */
|