| /* |
| * 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_ */ |