Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions arch/arm64/configs/qcom.config
Original file line number Diff line number Diff line change
Expand Up @@ -144,3 +144,5 @@ CONFIG_SCMI_QCOM_MEMLAT_DEVFREQ=m
# GPU Virtualization support
CONFIG_DRM_VIRTIO_GPU=m
CONFIG_DRM_VIRTIO_GPU_KMS=m

CONFIG_NVME_SPEED_SWITCH=y
10 changes: 10 additions & 0 deletions drivers/nvme/host/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -134,3 +134,13 @@ config NVME_APPLE

To compile this driver as a module, choose M here: the
module will be called nvme-apple.

config NVME_SPEED_SWITCH
bool "NVMe adaptive PCIe link rate switching"
depends on BLK_DEV_NVME
help
This provides support for dynamic PCIe link rate switching for NVMe
devices. When enabled, the NVMe driver can dynamically adjust the
PCIe link speed and width based on workload requirement.

If unsure, say N.
1 change: 1 addition & 0 deletions drivers/nvme/host/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ nvme-core-$(CONFIG_BLK_DEV_ZONED) += zns.o
nvme-core-$(CONFIG_FAULT_INJECTION_DEBUG_FS) += fault_inject.o
nvme-core-$(CONFIG_NVME_HWMON) += hwmon.o
nvme-core-$(CONFIG_NVME_HOST_AUTH) += auth.o
nvme-core-$(CONFIG_NVME_SPEED_SWITCH) += speed_switch.o

nvme-y += pci.o

Expand Down
4 changes: 4 additions & 0 deletions drivers/nvme/host/core.c
Original file line number Diff line number Diff line change
Expand Up @@ -4627,6 +4627,7 @@ static void nvme_scan_work(struct work_struct *work)
/* Re-read the ANA log page to not miss updates */
queue_work(nvme_wq, &ctrl->ana_work);
#endif
nvme_speed_switch_start(ctrl);
}

/*
Expand Down Expand Up @@ -5051,6 +5052,7 @@ EXPORT_SYMBOL_GPL(nvme_remove_io_tag_set);

void nvme_stop_ctrl(struct nvme_ctrl *ctrl)
{
nvme_speed_switch_exit(ctrl);
nvme_mpath_stop(ctrl);
nvme_auth_stop(ctrl);
nvme_stop_failfast_work(ctrl);
Expand Down Expand Up @@ -5266,6 +5268,8 @@ int nvme_add_ctrl(struct nvme_ctrl *ctrl)
nvme_fault_inject_init(&ctrl->fault_inject, dev_name(ctrl->device));
nvme_get_ctrl(ctrl);

nvme_speed_switch_init(ctrl);

return 0;
}
EXPORT_SYMBOL_GPL(nvme_add_ctrl);
Expand Down
50 changes: 50 additions & 0 deletions drivers/nvme/host/nvme.h
Original file line number Diff line number Diff line change
Expand Up @@ -331,6 +331,38 @@ enum nvme_ctrl_flags {
NVME_CTRL_FROZEN = 6,
};

#ifdef CONFIG_NVME_SPEED_SWITCH
struct nvme_speed_switch_stats {
u64 read_bytes;
u64 write_bytes;
};

struct nvme_speed_switch {
bool initialized;
bool enabled;
u8 max_speed;
u8 cur_speed;
u8 target_speed;
u8 min_speed;
u32 monitor_interval; /* ms */
u32 threshold; /* KB */
u32 up_cnt;
u32 down_cnt;
u32 up_threshold;
u32 down_threshold;
u32 idle_cnt;
struct timer_list timer;
struct work_struct work;
struct nvme_speed_switch_stats __percpu *stats;
atomic_t timer_active;
};

enum nvme_speed_timer_state {
NVME_SPEED_TIMER_INACTIVE,
NVME_SPEED_TIMER_ACTIVE,
};
#endif

struct nvme_ctrl {
bool comp_seen;
bool identified;
Expand Down Expand Up @@ -472,8 +504,23 @@ struct nvme_ctrl {
enum nvme_dctype dctype;

u16 awupf; /* 0's based value. */
#ifdef CONFIG_NVME_SPEED_SWITCH
struct nvme_speed_switch speed_switch;
#endif
};

#ifdef CONFIG_NVME_SPEED_SWITCH
void nvme_update_io_stats(struct nvme_ctrl *ctrl, struct request *req);
void nvme_speed_switch_start(struct nvme_ctrl *ctrl);
void nvme_speed_switch_init(struct nvme_ctrl *ctrl);
void nvme_speed_switch_exit(struct nvme_ctrl *ctrl);
#else
static inline void nvme_update_io_stats(struct nvme_ctrl *ctrl, struct request *req) {}
static inline void nvme_speed_switch_start(struct nvme_ctrl *ctrl) {}
static inline void nvme_speed_switch_init(struct nvme_ctrl *ctrl) {}
static inline void nvme_speed_switch_exit(struct nvme_ctrl *ctrl) {}
#endif

static inline enum nvme_ctrl_state nvme_ctrl_state(struct nvme_ctrl *ctrl)
{
return READ_ONCE(ctrl->state);
Expand Down Expand Up @@ -1029,6 +1076,9 @@ extern const struct attribute_group nvme_dev_attrs_group;
extern const struct attribute_group nvme_dev_diag_attrs_group;
extern const struct attribute_group *nvme_subsys_attrs_groups[];
extern const struct attribute_group *nvme_dev_attr_groups[];
#ifdef CONFIG_NVME_SPEED_SWITCH
extern const struct attribute_group nvme_speed_attr_group;
#endif
extern const struct block_device_operations nvme_bdev_ops;

void nvme_delete_ctrl_sync(struct nvme_ctrl *ctrl);
Expand Down
4 changes: 4 additions & 0 deletions drivers/nvme/host/pci.c
Original file line number Diff line number Diff line change
Expand Up @@ -1455,6 +1455,9 @@ static blk_status_t nvme_queue_rq(struct blk_mq_hw_ctx *hctx,
ret = nvme_prep_rq(req);
if (unlikely(ret))
return ret;

nvme_update_io_stats(&dev->ctrl, req);

spin_lock(&nvmeq->sq_lock);
nvme_sq_copy_cmd(nvmeq, &iod->cmd);
nvme_write_sq_db(nvmeq, bd->last);
Expand All @@ -1473,6 +1476,7 @@ static void nvme_submit_cmds(struct nvme_queue *nvmeq, struct rq_list *rqlist)
while ((req = rq_list_pop(rqlist))) {
struct nvme_iod *iod = blk_mq_rq_to_pdu(req);

nvme_update_io_stats(&nvmeq->dev->ctrl, req);
nvme_sq_copy_cmd(nvmeq, &iod->cmd);
}
nvme_write_sq_db(nvmeq, true);
Expand Down
Loading
Loading