Changeset View
Changeset View
Standalone View
Standalone View
head/sys/dev/nvme/nvme_ctrlr.c
Show First 20 Lines • Show All 74 Lines • ▼ Show 20 Lines | nvme_ctrlr_allocate_bar(struct nvme_controller *ctrlr) | ||||
*/ | */ | ||||
ctrlr->bar4_resource_id = PCIR_BAR(4); | ctrlr->bar4_resource_id = PCIR_BAR(4); | ||||
ctrlr->bar4_resource = bus_alloc_resource_any(ctrlr->dev, SYS_RES_MEMORY, | ctrlr->bar4_resource = bus_alloc_resource_any(ctrlr->dev, SYS_RES_MEMORY, | ||||
&ctrlr->bar4_resource_id, RF_ACTIVE); | &ctrlr->bar4_resource_id, RF_ACTIVE); | ||||
return (0); | return (0); | ||||
} | } | ||||
static void | static int | ||||
nvme_ctrlr_construct_admin_qpair(struct nvme_controller *ctrlr) | nvme_ctrlr_construct_admin_qpair(struct nvme_controller *ctrlr) | ||||
{ | { | ||||
struct nvme_qpair *qpair; | struct nvme_qpair *qpair; | ||||
uint32_t num_entries; | uint32_t num_entries; | ||||
int error; | |||||
qpair = &ctrlr->adminq; | qpair = &ctrlr->adminq; | ||||
num_entries = NVME_ADMIN_ENTRIES; | num_entries = NVME_ADMIN_ENTRIES; | ||||
TUNABLE_INT_FETCH("hw.nvme.admin_entries", &num_entries); | TUNABLE_INT_FETCH("hw.nvme.admin_entries", &num_entries); | ||||
/* | /* | ||||
* If admin_entries was overridden to an invalid value, revert it | * If admin_entries was overridden to an invalid value, revert it | ||||
* back to our default value. | * back to our default value. | ||||
*/ | */ | ||||
if (num_entries < NVME_MIN_ADMIN_ENTRIES || | if (num_entries < NVME_MIN_ADMIN_ENTRIES || | ||||
num_entries > NVME_MAX_ADMIN_ENTRIES) { | num_entries > NVME_MAX_ADMIN_ENTRIES) { | ||||
nvme_printf(ctrlr, "invalid hw.nvme.admin_entries=%d " | nvme_printf(ctrlr, "invalid hw.nvme.admin_entries=%d " | ||||
"specified\n", num_entries); | "specified\n", num_entries); | ||||
num_entries = NVME_ADMIN_ENTRIES; | num_entries = NVME_ADMIN_ENTRIES; | ||||
} | } | ||||
/* | /* | ||||
* The admin queue's max xfer size is treated differently than the | * The admin queue's max xfer size is treated differently than the | ||||
* max I/O xfer size. 16KB is sufficient here - maybe even less? | * max I/O xfer size. 16KB is sufficient here - maybe even less? | ||||
*/ | */ | ||||
nvme_qpair_construct(qpair, | error = nvme_qpair_construct(qpair, | ||||
0, /* qpair ID */ | 0, /* qpair ID */ | ||||
0, /* vector */ | 0, /* vector */ | ||||
num_entries, | num_entries, | ||||
NVME_ADMIN_TRACKERS, | NVME_ADMIN_TRACKERS, | ||||
ctrlr); | ctrlr); | ||||
return (error); | |||||
} | } | ||||
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; | ||||
union cap_lo_register cap_lo; | union cap_lo_register cap_lo; | ||||
int i, num_entries, num_trackers; | int i, error, num_entries, num_trackers; | ||||
num_entries = NVME_IO_ENTRIES; | num_entries = NVME_IO_ENTRIES; | ||||
TUNABLE_INT_FETCH("hw.nvme.io_entries", &num_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 may specify a smaller limit, so we need to check | * devices may specify a smaller limit, so we need to check | ||||
* the MQES field in the capabilities register. | * the MQES field in the capabilities register. | ||||
Show All 28 Lines | for (i = 0; i < ctrlr->num_io_queues; i++) { | ||||
/* | /* | ||||
* Admin queue has ID=0. IO queues start at ID=1 - | * Admin queue has ID=0. IO queues start at ID=1 - | ||||
* hence the 'i+1' here. | * hence the 'i+1' here. | ||||
* | * | ||||
* For I/O queues, use the controller-wide max_xfer_size | * For I/O queues, use the controller-wide max_xfer_size | ||||
* calculated in nvme_attach(). | * calculated in nvme_attach(). | ||||
*/ | */ | ||||
nvme_qpair_construct(qpair, | error = nvme_qpair_construct(qpair, | ||||
i+1, /* qpair ID */ | i+1, /* qpair ID */ | ||||
ctrlr->msix_enabled ? i+1 : 0, /* vector */ | ctrlr->msix_enabled ? i+1 : 0, /* vector */ | ||||
num_entries, | num_entries, | ||||
num_trackers, | num_trackers, | ||||
ctrlr); | ctrlr); | ||||
if (error) | |||||
return (error); | |||||
/* | /* | ||||
* Do not bother binding interrupts if we only have one I/O | * Do not bother binding interrupts if we only have one I/O | ||||
* interrupt thread for this controller. | * interrupt thread for this controller. | ||||
*/ | */ | ||||
if (ctrlr->num_io_queues > 1) | if (ctrlr->num_io_queues > 1) | ||||
bus_bind_intr(ctrlr->dev, qpair->res, | bus_bind_intr(ctrlr->dev, qpair->res, | ||||
i * ctrlr->num_cpus_per_ioq); | i * ctrlr->num_cpus_per_ioq); | ||||
▲ Show 20 Lines • Show All 913 Lines • ▼ Show 20 Lines | nvme_ctrlr_construct(struct nvme_controller *ctrlr, device_t dev) | ||||
TUNABLE_INT_FETCH("hw.nvme.retry_count", &nvme_retry_count); | TUNABLE_INT_FETCH("hw.nvme.retry_count", &nvme_retry_count); | ||||
ctrlr->enable_aborts = 0; | ctrlr->enable_aborts = 0; | ||||
TUNABLE_INT_FETCH("hw.nvme.enable_aborts", &ctrlr->enable_aborts); | TUNABLE_INT_FETCH("hw.nvme.enable_aborts", &ctrlr->enable_aborts); | ||||
nvme_ctrlr_setup_interrupts(ctrlr); | nvme_ctrlr_setup_interrupts(ctrlr); | ||||
ctrlr->max_xfer_size = NVME_MAX_XFER_SIZE; | ctrlr->max_xfer_size = NVME_MAX_XFER_SIZE; | ||||
nvme_ctrlr_construct_admin_qpair(ctrlr); | if (nvme_ctrlr_construct_admin_qpair(ctrlr) != 0) | ||||
return (ENXIO); | |||||
ctrlr->cdev = make_dev(&nvme_ctrlr_cdevsw, device_get_unit(dev), | ctrlr->cdev = make_dev(&nvme_ctrlr_cdevsw, device_get_unit(dev), | ||||
UID_ROOT, GID_WHEEL, 0600, "nvme%d", device_get_unit(dev)); | UID_ROOT, GID_WHEEL, 0600, "nvme%d", device_get_unit(dev)); | ||||
if (ctrlr->cdev == NULL) | if (ctrlr->cdev == NULL) | ||||
return (ENXIO); | return (ENXIO); | ||||
ctrlr->cdev->si_drv1 = (void *)ctrlr; | ctrlr->cdev->si_drv1 = (void *)ctrlr; | ||||
▲ Show 20 Lines • Show All 120 Lines • Show Last 20 Lines |