Skip to content

Commit 89b94a6

Browse files
damien-lemoalkeithbusch
authored andcommitted
nvmet: Implement interrupt coalescing feature support
The NVMe base specifications v2.1 mandate Supporting the interrupt coalescing feature (NVME_FEAT_IRQ_COALESCE) for PCI controllers. Introduce the data structure struct nvmet_feat_irq_coalesce to define the time and threshold (thr) fields of this feature and implement the functions nvmet_get_feat_irq_coalesce() and nvmet_set_feat_irq_coalesce() to get and set this feature. These functions respectively use the controller get_feature() and set_feature() operations to fill and handle the fields of struct nvmet_feat_irq_coalesce. While the Linux kernel nvme driver does not use this feature and thus will not complain if it is not implemented, other major OSes fail initializing the NVMe device if this feature support is missing. Support for this feature is prohibited for fabrics controllers. If a get feature or set feature command for this feature is received for a fabrics controller, the command is failed with an invalid field error. Suggested-by: Rick Wertenbroek <[email protected]> Signed-off-by: Damien Le Moal <[email protected]> Reviewed-by: Christoph Hellwig <[email protected]> Tested-by: Rick Wertenbroek <[email protected]> Tested-by: Manivannan Sadhasivam <[email protected]> Signed-off-by: Keith Busch <[email protected]>
1 parent 2f2b20f commit 89b94a6

File tree

2 files changed

+61
-2
lines changed

2 files changed

+61
-2
lines changed

drivers/nvme/target/admin-cmd.c

Lines changed: 51 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1282,6 +1282,27 @@ static u16 nvmet_set_feat_host_id(struct nvmet_req *req)
12821282
sizeof(req->sq->ctrl->hostid));
12831283
}
12841284

1285+
static u16 nvmet_set_feat_irq_coalesce(struct nvmet_req *req)
1286+
{
1287+
struct nvmet_ctrl *ctrl = req->sq->ctrl;
1288+
u32 cdw11 = le32_to_cpu(req->cmd->common.cdw11);
1289+
struct nvmet_feat_irq_coalesce irqc = {
1290+
.time = (cdw11 >> 8) & 0xff,
1291+
.thr = cdw11 & 0xff,
1292+
};
1293+
1294+
/*
1295+
* This feature is not supported for fabrics controllers and mandatory
1296+
* for PCI controllers.
1297+
*/
1298+
if (!nvmet_is_pci_ctrl(ctrl)) {
1299+
req->error_loc = offsetof(struct nvme_common_command, cdw10);
1300+
return NVME_SC_INVALID_FIELD | NVME_STATUS_DNR;
1301+
}
1302+
1303+
return ctrl->ops->set_feature(ctrl, NVME_FEAT_IRQ_COALESCE, &irqc);
1304+
}
1305+
12851306
void nvmet_execute_set_features(struct nvmet_req *req)
12861307
{
12871308
struct nvmet_subsys *subsys = nvmet_req_subsys(req);
@@ -1305,6 +1326,9 @@ void nvmet_execute_set_features(struct nvmet_req *req)
13051326
nvmet_set_result(req,
13061327
(subsys->max_qid - 1) | ((subsys->max_qid - 1) << 16));
13071328
break;
1329+
case NVME_FEAT_IRQ_COALESCE:
1330+
status = nvmet_set_feat_irq_coalesce(req);
1331+
break;
13081332
case NVME_FEAT_KATO:
13091333
status = nvmet_set_feat_kato(req);
13101334
break;
@@ -1349,6 +1373,30 @@ static u16 nvmet_get_feat_write_protect(struct nvmet_req *req)
13491373
return 0;
13501374
}
13511375

1376+
static u16 nvmet_get_feat_irq_coalesce(struct nvmet_req *req)
1377+
{
1378+
struct nvmet_ctrl *ctrl = req->sq->ctrl;
1379+
struct nvmet_feat_irq_coalesce irqc = { };
1380+
u16 status;
1381+
1382+
/*
1383+
* This feature is not supported for fabrics controllers and mandatory
1384+
* for PCI controllers.
1385+
*/
1386+
if (!nvmet_is_pci_ctrl(ctrl)) {
1387+
req->error_loc = offsetof(struct nvme_common_command, cdw10);
1388+
return NVME_SC_INVALID_FIELD | NVME_STATUS_DNR;
1389+
}
1390+
1391+
status = ctrl->ops->get_feature(ctrl, NVME_FEAT_IRQ_COALESCE, &irqc);
1392+
if (status != NVME_SC_SUCCESS)
1393+
return status;
1394+
1395+
nvmet_set_result(req, ((u32)irqc.time << 8) | (u32)irqc.thr);
1396+
1397+
return NVME_SC_SUCCESS;
1398+
}
1399+
13521400
void nvmet_get_feat_kato(struct nvmet_req *req)
13531401
{
13541402
nvmet_set_result(req, req->sq->ctrl->kato * 1000);
@@ -1383,13 +1431,14 @@ void nvmet_execute_get_features(struct nvmet_req *req)
13831431
break;
13841432
case NVME_FEAT_ERR_RECOVERY:
13851433
break;
1386-
case NVME_FEAT_IRQ_COALESCE:
1387-
break;
13881434
case NVME_FEAT_IRQ_CONFIG:
13891435
break;
13901436
case NVME_FEAT_WRITE_ATOMIC:
13911437
break;
13921438
#endif
1439+
case NVME_FEAT_IRQ_COALESCE:
1440+
status = nvmet_get_feat_irq_coalesce(req);
1441+
break;
13931442
case NVME_FEAT_ASYNC_EVENT:
13941443
nvmet_get_feat_async_event(req);
13951444
break;

drivers/nvme/target/nvmet.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -906,4 +906,14 @@ static inline void nvmet_pr_put_ns_pc_ref(struct nvmet_pr_per_ctrl_ref *pc_ref)
906906
{
907907
percpu_ref_put(&pc_ref->ref);
908908
}
909+
910+
/*
911+
* Data for the get_feature() and set_feature() operations of PCI target
912+
* controllers.
913+
*/
914+
struct nvmet_feat_irq_coalesce {
915+
u8 thr;
916+
u8 time;
917+
};
918+
909919
#endif /* _NVMET_H */

0 commit comments

Comments
 (0)