Commit f1ecd491 authored by Damien Le Moal's avatar Damien Le Moal Committed by Keith Busch
Browse files

nvmet: Implement interrupt config feature support



The NVMe base specifications v2.1 mandate supporting the interrupt
config feature (NVME_FEAT_IRQ_CONFIG) for PCI controllers. Introduce the
data structure struct nvmet_feat_irq_config to define the coalescing
disabled (cd) and interrupt vector (iv) fields of this feature and
implement the functions nvmet_get_feat_irq_config() and
nvmet_set_feat_irq_config() functions to get and set these fields. These
functions respectively use the controller get_feature() and
set_feature() operations to fill and handle the fields of struct
nvmet_feat_irq_config.

Support for this feature is prohibited for fabrics controllers. If a get
feature command or a set feature command for this feature is received
for a fabrics controller, the command is failed with an invalid field
error.

Signed-off-by: default avatarDamien Le Moal <dlemoal@kernel.org>
Reviewed-by: default avatarChristoph Hellwig <hch@lst.de>
Tested-by: default avatarRick Wertenbroek <rick.wertenbroek@gmail.com>
Tested-by: default avatarManivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
Signed-off-by: default avatarKeith Busch <kbusch@kernel.org>
parent 89b94a6c
Loading
Loading
Loading
Loading
+52 −2
Original line number Diff line number Diff line
@@ -1303,6 +1303,27 @@ static u16 nvmet_set_feat_irq_coalesce(struct nvmet_req *req)
	return ctrl->ops->set_feature(ctrl, NVME_FEAT_IRQ_COALESCE, &irqc);
}

static u16 nvmet_set_feat_irq_config(struct nvmet_req *req)
{
	struct nvmet_ctrl *ctrl = req->sq->ctrl;
	u32 cdw11 = le32_to_cpu(req->cmd->common.cdw11);
	struct nvmet_feat_irq_config irqcfg = {
		.iv = cdw11 & 0xffff,
		.cd = (cdw11 >> 16) & 0x1,
	};

	/*
	 * This feature is not supported for fabrics controllers and mandatory
	 * for PCI controllers.
	 */
	if (!nvmet_is_pci_ctrl(ctrl)) {
		req->error_loc = offsetof(struct nvme_common_command, cdw10);
		return NVME_SC_INVALID_FIELD | NVME_STATUS_DNR;
	}

	return ctrl->ops->set_feature(ctrl, NVME_FEAT_IRQ_CONFIG, &irqcfg);
}

void nvmet_execute_set_features(struct nvmet_req *req)
{
	struct nvmet_subsys *subsys = nvmet_req_subsys(req);
@@ -1329,6 +1350,9 @@ void nvmet_execute_set_features(struct nvmet_req *req)
	case NVME_FEAT_IRQ_COALESCE:
		status = nvmet_set_feat_irq_coalesce(req);
		break;
	case NVME_FEAT_IRQ_CONFIG:
		status = nvmet_set_feat_irq_config(req);
		break;
	case NVME_FEAT_KATO:
		status = nvmet_set_feat_kato(req);
		break;
@@ -1397,6 +1421,31 @@ static u16 nvmet_get_feat_irq_coalesce(struct nvmet_req *req)
	return NVME_SC_SUCCESS;
}

static u16 nvmet_get_feat_irq_config(struct nvmet_req *req)
{
	struct nvmet_ctrl *ctrl = req->sq->ctrl;
	u32 iv = le32_to_cpu(req->cmd->common.cdw11) & 0xffff;
	struct nvmet_feat_irq_config irqcfg = { .iv = iv };
	u16 status;

	/*
	 * This feature is not supported for fabrics controllers and mandatory
	 * for PCI controllers.
	 */
	if (!nvmet_is_pci_ctrl(ctrl)) {
		req->error_loc = offsetof(struct nvme_common_command, cdw10);
		return NVME_SC_INVALID_FIELD | NVME_STATUS_DNR;
	}

	status = ctrl->ops->get_feature(ctrl, NVME_FEAT_IRQ_CONFIG, &irqcfg);
	if (status != NVME_SC_SUCCESS)
		return status;

	nvmet_set_result(req, ((u32)irqcfg.cd << 16) | iv);

	return NVME_SC_SUCCESS;
}

void nvmet_get_feat_kato(struct nvmet_req *req)
{
	nvmet_set_result(req, req->sq->ctrl->kato * 1000);
@@ -1431,14 +1480,15 @@ void nvmet_execute_get_features(struct nvmet_req *req)
		break;
	case NVME_FEAT_ERR_RECOVERY:
		break;
	case NVME_FEAT_IRQ_CONFIG:
		break;
	case NVME_FEAT_WRITE_ATOMIC:
		break;
#endif
	case NVME_FEAT_IRQ_COALESCE:
		status = nvmet_get_feat_irq_coalesce(req);
		break;
	case NVME_FEAT_IRQ_CONFIG:
		status = nvmet_get_feat_irq_config(req);
		break;
	case NVME_FEAT_ASYNC_EVENT:
		nvmet_get_feat_async_event(req);
		break;
+5 −0
Original line number Diff line number Diff line
@@ -916,4 +916,9 @@ struct nvmet_feat_irq_coalesce {
	u8		time;
};

struct nvmet_feat_irq_config {
	u16		iv;
	bool		cd;
};

#endif /* _NVMET_H */