NVMe: Introduce CMB allocation scheme
Subsystems (2)
v2 cover NVMe: Introduce CMB allocation scheme
This set is a continuation of v1 introduced in December [1]. v1 was missing the controls to reduce the queue depth, and so would allow tags to be issued above the depth of the CMB allocated queues.
v2 drops patch 3 of v1 which created a cmb_resources file with a layout similar to the pci_dev resource file.
This set was tested with QEMU with NVMe device emulation [2]
Applies to Jen's for-4.6/drivers [3]
[1] http://lists.infradead.org/pipermail/linux-nvme/2015-December/003510.html
[2] git://git.infradead.org/users/kbusch/qemu-nvme.git
[3] https://git.kernel.org/cgit/linux/kernel/git/axboe/linux-block.git/log/?h=for-4.6/drivers
Jon Derrick (3):
blk-mq: helper to reduce queue depth on all hardware contexts
NVMe: Introduce sysfs entries for submission queues in CMB
NVMe: Generate resource tree for CMB
block/blk-mq.c | 20 ++++ drivers/nvme/host/core.c | 136 ++++++++++++++++++++++++++- drivers/nvme/host/nvme.h | 22 +++++ drivers/nvme/host/pci.c | 238 ++++++++++++++++++++++++++++++++--------------- include/linux/blk-mq.h | 1 + 5 files changed, 339 insertions(+), 78 deletions(-)
Signature · 1 line
2.1.4
PATCH v2 1/3 blk-mq: helper to reduce queue depth on all hardware contexts
Creates helper that limits the tags on all request_queues attached to the tagset. This functionality is used to reassign queues in host memory to controller memory buffers with lower queue depths.
--- block/blk-mq.c | 20 ++++++++++++++++++++ include/linux/blk-mq.h | 1 + 2 files changed, 21 insertions(+)
block/blk-mq.c +20 -0
@@ -2345,6 +2345,26 @@ int blk_mq_update_nr_requests(struct request_queue *q, unsigned int nr)return ret; } +void blk_mq_update_nr_hw_requests (struct blk_mq_tag_set *set, +int nr_requests) +{ +struct request_queue *q; + +if (nr_requests < set->reserved_tags +1 || + nr_requests == set->queue_depth) +return ; + +list_for_each_entry (q, &set->tag_list, tag_set_list) +blk_mq_freeze_queue (q); + +list_for_each_entry (q, &set->tag_list, tag_set_list) +blk_mq_update_nr_requests (q, nr_requests); + +list_for_each_entry (q, &set->tag_list, tag_set_list) +blk_mq_unfreeze_queue (q); +} +EXPORT_SYMBOL_GPL (blk_mq_update_nr_hw_requests); +void blk_mq_update_nr_hw_queues (struct blk_mq_tag_set *set,int nr_hw_queues) {struct request_queue *q;
include/linux/blk-mq.h +1 -0
@@ -244,6 +244,7 @@ void blk_mq_freeze_queue(struct request_queue *q);void blk_mq_unfreeze_queue (struct request_queue *q);void blk_mq_freeze_queue_start (struct request_queue *q); +void blk_mq_update_nr_hw_requests (struct blk_mq_tag_set *set,int nr_requests);void blk_mq_update_nr_hw_queues (struct blk_mq_tag_set *set,int nr_hw_queues);/*
Signature · 1 line
2.1.4
PATCH v2 2/3 NVMe: Introduce sysfs entries for submission queues in CMB
In reply to Jon DerrickCurrently submission queues are always mapped to the CMB if possible and allowed by a module parameter. To allow userspace more control over the CMB, this patch introduces a sysfs/cmb framework into the core nvme code and refactors the pci portion.
If the controller supports SQes in the CMB, sysfs files cmb_sq_depth and cmb_sq_offset are visible. To apply changes to the queues, users must write the sysfs reset_controller entry after changing cmb parameters.
--- drivers/nvme/host/core.c | 136 +++++++++++++++++++++++++++++++- drivers/nvme/host/nvme.h | 23 ++++++ drivers/nvme/host/pci.c | 200 ++++++++++++++++++++++++++++++++--------------- 3 files changed, 292 insertions(+), 67 deletions(-)
drivers/nvme/host/core.c +134 -2
@@ -1035,6 +1035,89 @@ static ssize_t nvme_sysfs_reset(struct device *dev, } static DEVICE_ATTR(reset_controller, S_IWUSR, NULL, nvme_sysfs_reset); +static ssize_t nvme_cmb_sq_depth_show (struct device *dev, +struct device_attribute *attr, +char *buf) +{ +struct nvme_ctrl *ctrl =dev_get_drvdata (dev); +struct nvme_cmb *cmb = ctrl->cmb; +return sprintf (buf,"%u\n" , cmb->sq_depth); +} + +static ssize_t nvme_cmb_sq_depth_store (struct device *dev, +struct device_attribute *attr, +const char *buf,size_t count) +{ +struct nvme_ctrl *ctrl =dev_get_drvdata (dev); +struct nvme_cmb *cmb = ctrl->cmb; +u32 sq_depth; + +sscanf (buf,"%u" , &sq_depth); +if (sq_depth >0xffff ) +return -EINVAL ; + +if (sq_depth >0 && sq_depth < ctrl->tagset->reserved_tags +1 ) +return -EINVAL ; + + cmb->sq_depth = sq_depth; +return count; +} +static DEVICE_ATTR(cmb_sq_depth, S_IWUSR | S_IRUGO, nvme_cmb_sq_depth_show, + nvme_cmb_sq_depth_store); + +static ssize_t nvme_cmb_sq_offset_show (struct device *dev, +struct device_attribute *attr, +char *buf) +{ +struct nvme_ctrl *ctrl =dev_get_drvdata (dev); +struct nvme_cmb *cmb = ctrl->cmb; +return sprintf (buf,"%llu\n" , cmb->sq_offset); +} + +static ssize_t nvme_cmb_sq_offset_store (struct device *dev, +struct device_attribute *attr, +const char *buf,size_t count) +{ +struct nvme_ctrl *ctrl =dev_get_drvdata (dev); +struct nvme_cmb *cmb = ctrl->cmb; +u64 sq_offset; + +sscanf (buf,"%llu" , &sq_offset); +if (sq_offset >= cmb->size) +return -EINVAL ; + + cmb->sq_offset = sq_offset; +return count; +} +static DEVICE_ATTR(cmb_sq_offset, S_IWUSR | S_IRUGO, nvme_cmb_sq_offset_show, + nvme_cmb_sq_offset_store); + +static struct attribute *nvme_cmb_attrs[] = { + &dev_attr_cmb_sq_depth.attr, + &dev_attr_cmb_sq_offset.attr, +NULL +}; + +static umode_t nvme_cmb_attrs_are_visible (struct kobject *kobj, +struct attribute *a,int n) +{ +struct device *dev =kobj_to_dev (kobj); +struct nvme_ctrl *ctrl =dev_get_drvdata (dev); +struct nvme_cmb *cmb = ctrl->cmb; + +if ((a == &dev_attr_cmb_sq_depth.attr) || + (a == &dev_attr_cmb_sq_offset.attr)) { +if (!(cmb->flags &NVME_CMB_SQ_SUPPORTED )) +return 0 ; + } +return a->mode; +} + +static struct attribute_group nvme_cmb_attr_group = { + .attrs = nvme_cmb_attrs, + .is_visible = nvme_cmb_attrs_are_visible, +}; +static ssize_t uuid_show (struct device *dev,struct device_attribute *attr,char *buf) {
@@ -1066,7 +1149,7 @@ static struct attribute *nvme_ns_attrs[] = { NULL, }; -static umode_t nvme_attrs_are_visible (struct kobject *kobj, +static umode_t nvme_ns_attrs_are_visible (struct kobject *kobj,struct attribute *a,int n) { struct device *dev = container_of(kobj, struct device, kobj);
@@ -1085,7 +1168,7 @@ static umode_t nvme_attrs_are_visible(struct kobject *kobj,static const struct attribute_group nvme_ns_attr_group = { .attrs = nvme_ns_attrs, - .is_visible = nvme_attrs_are_visible, + .is_visible = nvme_ns_attrs_are_visible, };#define nvme_show_function (field) \
@@ -1344,6 +1427,47 @@ void nvme_remove_namespaces(struct nvme_ctrl *ctrl) }EXPORT_SYMBOL_GPL (nvme_remove_namespaces); +static int nvme_init_cmb (struct nvme_ctrl *ctrl) +{ +/* Preserve across device resets */ +if (ctrl->cmb) +return 0 ; + + ctrl->cmb =kzalloc (sizeof (*ctrl->cmb),GFP_KERNEL ); +if (!ctrl->cmb) +return -ENOMEM ; + +return 0 ; +} + +static void nvme_release_cmb (struct nvme_ctrl *ctrl) +{ +if (ctrl->cmb) { +kfree (ctrl->cmb); + ctrl->cmb =NULL ; + } +} + +void nvme_map_cmb (struct nvme_ctrl *ctrl) +{ +struct device *dev = ctrl->device; + +if (ctrl->ops->map_cmb (ctrl)) +return ; + +if (sysfs_create_group (&dev->kobj, &nvme_cmb_attr_group)) +dev_warn (dev,"failed to create sysfs group for CMB\n" ); +} +EXPORT_SYMBOL_GPL (nvme_map_cmb); + +void nvme_unmap_cmb (struct nvme_ctrl *ctrl) +{ +struct device *dev = ctrl->device; + ctrl->ops->unmap_cmb (ctrl); +sysfs_remove_group (&dev->kobj, &nvme_cmb_attr_group); +} +EXPORT_SYMBOL_GPL (nvme_unmap_cmb); +static DEFINE_IDA (nvme_instance_ida);static int nvme_set_instance (struct nvme_ctrl *ctrl)
@@ -1388,6 +1512,7 @@ static void nvme_free_ctrl(struct kref *kref) struct nvme_ctrl *ctrl = container_of(kref, struct nvme_ctrl, kref);put_device (ctrl->device); +nvme_release_cmb (ctrl);nvme_release_instance (ctrl); ctrl->ops->free_ctrl (ctrl);
@@ -1430,11 +1555,18 @@ int nvme_init_ctrl(struct nvme_ctrl *ctrl, struct device *dev, }get_device (ctrl->device); + ret =nvme_init_cmb (ctrl); +if (ret) + goto out_destroy_device; +spin_lock (&dev_list_lock);list_add_tail (&ctrl->node, &nvme_ctrl_list);spin_unlock (&dev_list_lock);return 0 ; +out_destroy_device: +put_device (ctrl->device); +device_destroy (nvme_class,MKDEV (nvme_char_major, ctrl->instance)); out_release_instance:nvme_release_instance (ctrl); out:
drivers/nvme/host/nvme.h +23 -0
@@ -72,6 +72,7 @@ struct nvme_ctrl {struct mutex namespaces_mutex;struct device *device;/* char device */ struct list_head node; +struct nvme_cmb *cmb;char name[12 ];char serial[20 ];
@@ -116,6 +117,23 @@ struct nvme_ns {u32 mode_select_block_len; }; +struct nvme_cmb { +void __iomem *cmb; +dma_addr_t dma_addr; +u64 size; +u64 sq_offset; +u16 sq_depth; +unsigned long flags; +}; + +enum nvme_cmb_flags { +NVME_CMB_SQ_SUPPORTED = (1 <<0 ), +NVME_CMB_CQ_SUPPORTED = (1 <<1 ), +NVME_CMB_WD_SUPPORTED = (1 <<2 ), +NVME_CMB_RD_SUPPORTED = (1 <<3 ), +NVME_CMB_PRP_SUPPORTED = (1 <<4 ), +}; +struct nvme_ctrl_ops {struct module *module;int (*reg_read32)(struct nvme_ctrl *ctrl,u32 off,u32 *val);
@@ -124,6 +142,8 @@ struct nvme_ctrl_ops {bool (*io_incapable)(struct nvme_ctrl *ctrl);int (*reset_ctrl)(struct nvme_ctrl *ctrl);void (*free_ctrl)(struct nvme_ctrl *ctrl); +int (*map_cmb)(struct nvme_ctrl *ctrl); +void (*unmap_cmb)(struct nvme_ctrl *ctrl); };static inline bool nvme_ctrl_ready (struct nvme_ctrl *ctrl)
@@ -239,6 +259,9 @@ int nvme_init_identify(struct nvme_ctrl *ctrl);void nvme_scan_namespaces (struct nvme_ctrl *ctrl);void nvme_remove_namespaces (struct nvme_ctrl *ctrl); +void nvme_map_cmb (struct nvme_ctrl *ctrl); +void nvme_unmap_cmb (struct nvme_ctrl *ctrl); +void nvme_stop_queues (struct nvme_ctrl *ctrl);void nvme_start_queues (struct nvme_ctrl *ctrl);
drivers/nvme/host/pci.c +135 -65
336 lines not on this page · raw message
Signature · 1 line
2.1.4
PATCH v2 3/3 NVMe: Generate resource tree for CMB
In reply to Jon DerrickMaintains a resource tree for CMB resources. This new scheme uses resource/region based allocation to manage CMB memory for in-driver usage. For the NVMe PCIe driver, this information is exposed through /proc/iomem.
--- drivers/nvme/host/core.c | 2 +- drivers/nvme/host/nvme.h | 3 +- drivers/nvme/host/pci.c | 76 +++++++++++++++++++++++++++++------------------- 3 files changed, 48 insertions(+), 33 deletions(-)
drivers/nvme/host/core.c +1 -1
@@ -1083,7 +1083,7 @@ static ssize_t nvme_cmb_sq_offset_store(struct device *dev,u64 sq_offset;sscanf (buf,"%llu" , &sq_offset); -if (sq_offset >= cmb->size) +if (sq_offset >=resource_size (cmb->res))return -EINVAL ; cmb->sq_offset = sq_offset;
drivers/nvme/host/nvme.h +1 -2
@@ -118,9 +118,8 @@ struct nvme_ns { };struct nvme_cmb { +struct resource *res;void __iomem *cmb; -dma_addr_t dma_addr; -u64 size;u64 sq_offset;u16 sq_depth;unsigned long flags;
drivers/nvme/host/pci.c +46 -30
168 lines not on this page · raw message
Signature · 1 line
2.1.4