Changeset View
Changeset View
Standalone View
Standalone View
sys/dev/nvme/nvme_ctrlr.c
Show First 20 Lines • Show All 84 Lines • ▼ Show 20 Lines | |||||
} | } | ||||
static int | static int | ||||
nvme_ctrlr_construct_io_qpairs(struct nvme_controller *ctrlr) | nvme_ctrlr_construct_io_qpairs(struct nvme_controller *ctrlr) | ||||
{ | { | ||||
struct nvme_qpair *qpair; | struct nvme_qpair *qpair; | ||||
uint32_t cap_lo; | uint32_t cap_lo; | ||||
uint16_t mqes; | uint16_t mqes; | ||||
int i, error, num_entries, num_trackers; | int i, error, num_entries, num_trackers, max_entries; | ||||
num_entries = NVME_IO_ENTRIES; | |||||
TUNABLE_INT_FETCH("hw.nvme.io_entries", &num_entries); | |||||
/* | /* | ||||
* NVMe spec sets a hard limit of 64K max entries, but | * NVMe spec sets a hard limit of 64K max entries, but devices | ||||
* devices may specify a smaller limit, so we need to check | * may specify a smaller limit, so we need to check the MQES | ||||
* the MQES field in the capabilities register. | * field in the capabilities register. We have to cap the | ||||
* number of entries to the current stride allows for in BAR | |||||
* 0/1, otherwise the remainder entries are inaccessable. MQES | |||||
* should reflect this, and this is just a fail-safe. | |||||
*/ | */ | ||||
max_entries = | |||||
(rman_get_size(ctrlr->resource) - nvme_mmio_offsetof(doorbell[0])) / | |||||
(1 << (ctrlr->dstrd + 1)); | |||||
num_entries = NVME_IO_ENTRIES; | |||||
TUNABLE_INT_FETCH("hw.nvme.io_entries", &num_entries); | |||||
cap_lo = nvme_mmio_read_4(ctrlr, cap_lo); | cap_lo = nvme_mmio_read_4(ctrlr, cap_lo); | ||||
mqes = NVME_CAP_LO_MQES(cap_lo); | mqes = NVME_CAP_LO_MQES(cap_lo); | ||||
num_entries = min(num_entries, mqes + 1); | num_entries = min(num_entries, mqes + 1); | ||||
num_entries = min(num_entries, max_entries); | |||||
imp: This should be min. We want the smaller of these two.
| |||||
num_trackers = NVME_IO_TRACKERS; | num_trackers = NVME_IO_TRACKERS; | ||||
TUNABLE_INT_FETCH("hw.nvme.io_trackers", &num_trackers); | TUNABLE_INT_FETCH("hw.nvme.io_trackers", &num_trackers); | ||||
num_trackers = max(num_trackers, NVME_MIN_IO_TRACKERS); | num_trackers = max(num_trackers, NVME_MIN_IO_TRACKERS); | ||||
num_trackers = min(num_trackers, NVME_MAX_IO_TRACKERS); | num_trackers = min(num_trackers, NVME_MAX_IO_TRACKERS); | ||||
/* | /* | ||||
* No need to have more trackers than entries in the submit queue. | * No need to have more trackers than entries in the submit | ||||
* Note also that for a queue size of N, we can only have (N-1) | * queue. Note also that for a queue size of N, we can only | ||||
* commands outstanding, hence the "-1" here. | * have (N-1) commands outstanding, hence the "-1" here. | ||||
*/ | */ | ||||
num_trackers = min(num_trackers, (num_entries-1)); | num_trackers = min(num_trackers, (num_entries-1)); | ||||
/* | /* | ||||
* Our best estimate for the maximum number of I/Os that we should | * Our best estimate for the maximum number of I/Os that we should | ||||
* normally have in flight at one time. This should be viewed as a hint, | * normally have in flight at one time. This should be viewed as a hint, | ||||
* not a hard limit and will need to be revisited when the upper layers | * not a hard limit and will need to be revisited when the upper layers | ||||
* of the storage system grows multi-queue support. | * of the storage system grows multi-queue support. | ||||
▲ Show 20 Lines • Show All 991 Lines • ▼ Show 20 Lines | |||||
int | int | ||||
nvme_ctrlr_construct(struct nvme_controller *ctrlr, device_t dev) | nvme_ctrlr_construct(struct nvme_controller *ctrlr, device_t dev) | ||||
{ | { | ||||
struct make_dev_args md_args; | struct make_dev_args md_args; | ||||
uint32_t cap_lo; | uint32_t cap_lo; | ||||
uint32_t cap_hi; | uint32_t cap_hi; | ||||
uint32_t to; | uint32_t to; | ||||
uint8_t dstrd; | |||||
uint8_t mpsmin; | uint8_t mpsmin; | ||||
int status, timeout_period; | int status, timeout_period; | ||||
ctrlr->dev = dev; | ctrlr->dev = dev; | ||||
mtx_init(&ctrlr->lock, "nvme ctrlr lock", NULL, MTX_DEF); | mtx_init(&ctrlr->lock, "nvme ctrlr lock", NULL, MTX_DEF); | ||||
/* | |||||
* Software emulators may set the doorbell stride to something | |||||
* other than zero, but this driver is not set up to handle that. | |||||
*/ | |||||
cap_hi = nvme_mmio_read_4(ctrlr, cap_hi); | cap_hi = nvme_mmio_read_4(ctrlr, cap_hi); | ||||
dstrd = NVME_CAP_HI_DSTRD(cap_hi); | ctrlr->dstrd = NVME_CAP_HI_DSTRD(cap_hi) + 2; | ||||
if (dstrd != 0) | |||||
return (ENXIO); | |||||
mpsmin = NVME_CAP_HI_MPSMIN(cap_hi); | mpsmin = NVME_CAP_HI_MPSMIN(cap_hi); | ||||
ctrlr->min_page_size = 1 << (12 + mpsmin); | ctrlr->min_page_size = 1 << (12 + mpsmin); | ||||
/* Get ready timeout value from controller, in units of 500ms. */ | /* Get ready timeout value from controller, in units of 500ms. */ | ||||
cap_lo = nvme_mmio_read_4(ctrlr, cap_lo); | cap_lo = nvme_mmio_read_4(ctrlr, cap_lo); | ||||
to = NVME_CAP_LO_TO(cap_lo) + 1; | to = NVME_CAP_LO_TO(cap_lo) + 1; | ||||
ctrlr->ready_timeout_in_ms = to * 500; | ctrlr->ready_timeout_in_ms = to * 500; | ||||
▲ Show 20 Lines • Show All 254 Lines • Show Last 20 Lines |
This should be min. We want the smaller of these two.