]> www.infradead.org Git - nvme.git/commitdiff
nvmet: Implement interrupt config feature support
authorDamien Le Moal <dlemoal@kernel.org>
Sat, 4 Jan 2025 04:59:48 +0000 (13:59 +0900)
committerKeith Busch <kbusch@kernel.org>
Sat, 11 Jan 2025 03:30:49 +0000 (19:30 -0800)
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: Damien Le Moal <dlemoal@kernel.org>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Tested-by: Rick Wertenbroek <rick.wertenbroek@gmail.com>
Tested-by: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
Signed-off-by: Keith Busch <kbusch@kernel.org>
drivers/nvme/target/admin-cmd.c
drivers/nvme/target/nvmet.h

index eff9fd2e81ed5e52b36a448a7fa28f9e3fa8f945..8b8ec33330b238067f35873bafb773391354410a 100644 (file)
@@ -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;
index 555c09b11dbe6196b4c8a3dfd56c25629381c9b1..999a4ebf597efae0517fdef2f38a42f48d65b02c 100644 (file)
@@ -916,4 +916,9 @@ struct nvmet_feat_irq_coalesce {
        u8              time;
 };
 
+struct nvmet_feat_irq_config {
+       u16             iv;
+       bool            cd;
+};
+
 #endif /* _NVMET_H */