aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChristoph Hellwig <hch@lst.de>2017-02-05 12:15:26 -0500
committerMichael S. Tsirkin <mst@redhat.com>2017-02-27 13:54:06 -0500
commit0d9f0a52c8b9f7a003fe1650b7d5fb8518efabe0 (patch)
treefab497b3fc1a878f5a79e7512e95c90fb36713b5
parentad71473d9c43725c917fc5a86d54ceb7001ee28c (diff)
virtio_scsi: use virtio IRQ affinity
Use automatic IRQ affinity assignment in the virtio layer if available, and build the blk-mq queues based on it. Signed-off-by: Christoph Hellwig <hch@lst.de> Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
-rw-r--r--drivers/scsi/virtio_scsi.c126
-rw-r--r--include/linux/cpuhotplug.h1
2 files changed, 12 insertions, 115 deletions
diff --git a/drivers/scsi/virtio_scsi.c b/drivers/scsi/virtio_scsi.c
index c9c5ea0611e9..939c47df73fa 100644
--- a/drivers/scsi/virtio_scsi.c
+++ b/drivers/scsi/virtio_scsi.c
@@ -18,6 +18,7 @@
18#include <linux/module.h> 18#include <linux/module.h>
19#include <linux/slab.h> 19#include <linux/slab.h>
20#include <linux/mempool.h> 20#include <linux/mempool.h>
21#include <linux/interrupt.h>
21#include <linux/virtio.h> 22#include <linux/virtio.h>
22#include <linux/virtio_ids.h> 23#include <linux/virtio_ids.h>
23#include <linux/virtio_config.h> 24#include <linux/virtio_config.h>
@@ -29,6 +30,7 @@
29#include <scsi/scsi_cmnd.h> 30#include <scsi/scsi_cmnd.h>
30#include <scsi/scsi_tcq.h> 31#include <scsi/scsi_tcq.h>
31#include <linux/seqlock.h> 32#include <linux/seqlock.h>
33#include <linux/blk-mq-virtio.h>
32 34
33#define VIRTIO_SCSI_MEMPOOL_SZ 64 35#define VIRTIO_SCSI_MEMPOOL_SZ 64
34#define VIRTIO_SCSI_EVENT_LEN 8 36#define VIRTIO_SCSI_EVENT_LEN 8
@@ -108,7 +110,6 @@ struct virtio_scsi {
108 bool affinity_hint_set; 110 bool affinity_hint_set;
109 111
110 struct hlist_node node; 112 struct hlist_node node;
111 struct hlist_node node_dead;
112 113
113 /* Protected by event_vq lock */ 114 /* Protected by event_vq lock */
114 bool stop_events; 115 bool stop_events;
@@ -118,7 +119,6 @@ struct virtio_scsi {
118 struct virtio_scsi_vq req_vqs[]; 119 struct virtio_scsi_vq req_vqs[];
119}; 120};
120 121
121static enum cpuhp_state virtioscsi_online;
122static struct kmem_cache *virtscsi_cmd_cache; 122static struct kmem_cache *virtscsi_cmd_cache;
123static mempool_t *virtscsi_cmd_pool; 123static mempool_t *virtscsi_cmd_pool;
124 124
@@ -766,6 +766,13 @@ static void virtscsi_target_destroy(struct scsi_target *starget)
766 kfree(tgt); 766 kfree(tgt);
767} 767}
768 768
769static int virtscsi_map_queues(struct Scsi_Host *shost)
770{
771 struct virtio_scsi *vscsi = shost_priv(shost);
772
773 return blk_mq_virtio_map_queues(&shost->tag_set, vscsi->vdev, 2);
774}
775
769static struct scsi_host_template virtscsi_host_template_single = { 776static struct scsi_host_template virtscsi_host_template_single = {
770 .module = THIS_MODULE, 777 .module = THIS_MODULE,
771 .name = "Virtio SCSI HBA", 778 .name = "Virtio SCSI HBA",
@@ -801,6 +808,7 @@ static struct scsi_host_template virtscsi_host_template_multi = {
801 .use_clustering = ENABLE_CLUSTERING, 808 .use_clustering = ENABLE_CLUSTERING,
802 .target_alloc = virtscsi_target_alloc, 809 .target_alloc = virtscsi_target_alloc,
803 .target_destroy = virtscsi_target_destroy, 810 .target_destroy = virtscsi_target_destroy,
811 .map_queues = virtscsi_map_queues,
804 .track_queue_depth = 1, 812 .track_queue_depth = 1,
805}; 813};
806 814
@@ -817,80 +825,6 @@ static struct scsi_host_template virtscsi_host_template_multi = {
817 virtio_cwrite(vdev, struct virtio_scsi_config, fld, &__val); \ 825 virtio_cwrite(vdev, struct virtio_scsi_config, fld, &__val); \
818 } while(0) 826 } while(0)
819 827
820static void __virtscsi_set_affinity(struct virtio_scsi *vscsi, bool affinity)
821{
822 int i;
823 int cpu;
824
825 /* In multiqueue mode, when the number of cpu is equal
826 * to the number of request queues, we let the qeueues
827 * to be private to one cpu by setting the affinity hint
828 * to eliminate the contention.
829 */
830 if ((vscsi->num_queues == 1 ||
831 vscsi->num_queues != num_online_cpus()) && affinity) {
832 if (vscsi->affinity_hint_set)
833 affinity = false;
834 else
835 return;
836 }
837
838 if (affinity) {
839 i = 0;
840 for_each_online_cpu(cpu) {
841 virtqueue_set_affinity(vscsi->req_vqs[i].vq, cpu);
842 i++;
843 }
844
845 vscsi->affinity_hint_set = true;
846 } else {
847 for (i = 0; i < vscsi->num_queues; i++) {
848 if (!vscsi->req_vqs[i].vq)
849 continue;
850
851 virtqueue_set_affinity(vscsi->req_vqs[i].vq, -1);
852 }
853
854 vscsi->affinity_hint_set = false;
855 }
856}
857
858static void virtscsi_set_affinity(struct virtio_scsi *vscsi, bool affinity)
859{
860 get_online_cpus();
861 __virtscsi_set_affinity(vscsi, affinity);
862 put_online_cpus();
863}
864
865static int virtscsi_cpu_online(unsigned int cpu, struct hlist_node *node)
866{
867 struct virtio_scsi *vscsi = hlist_entry_safe(node, struct virtio_scsi,
868 node);
869 __virtscsi_set_affinity(vscsi, true);
870 return 0;
871}
872
873static int virtscsi_cpu_notif_add(struct virtio_scsi *vi)
874{
875 int ret;
876
877 ret = cpuhp_state_add_instance(virtioscsi_online, &vi->node);
878 if (ret)
879 return ret;
880
881 ret = cpuhp_state_add_instance(CPUHP_VIRT_SCSI_DEAD, &vi->node_dead);
882 if (ret)
883 cpuhp_state_remove_instance(virtioscsi_online, &vi->node);
884 return ret;
885}
886
887static void virtscsi_cpu_notif_remove(struct virtio_scsi *vi)
888{
889 cpuhp_state_remove_instance_nocalls(virtioscsi_online, &vi->node);
890 cpuhp_state_remove_instance_nocalls(CPUHP_VIRT_SCSI_DEAD,
891 &vi->node_dead);
892}
893
894static void virtscsi_init_vq(struct virtio_scsi_vq *virtscsi_vq, 828static void virtscsi_init_vq(struct virtio_scsi_vq *virtscsi_vq,
895 struct virtqueue *vq) 829 struct virtqueue *vq)
896{ 830{
@@ -900,14 +834,8 @@ static void virtscsi_init_vq(struct virtio_scsi_vq *virtscsi_vq,
900 834
901static void virtscsi_remove_vqs(struct virtio_device *vdev) 835static void virtscsi_remove_vqs(struct virtio_device *vdev)
902{ 836{
903 struct Scsi_Host *sh = virtio_scsi_host(vdev);
904 struct virtio_scsi *vscsi = shost_priv(sh);
905
906 virtscsi_set_affinity(vscsi, false);
907
908 /* Stop all the virtqueues. */ 837 /* Stop all the virtqueues. */
909 vdev->config->reset(vdev); 838 vdev->config->reset(vdev);
910
911 vdev->config->del_vqs(vdev); 839 vdev->config->del_vqs(vdev);
912} 840}
913 841
@@ -920,6 +848,7 @@ static int virtscsi_init(struct virtio_device *vdev,
920 vq_callback_t **callbacks; 848 vq_callback_t **callbacks;
921 const char **names; 849 const char **names;
922 struct virtqueue **vqs; 850 struct virtqueue **vqs;
851 struct irq_affinity desc = { .pre_vectors = 2 };
923 852
924 num_vqs = vscsi->num_queues + VIRTIO_SCSI_VQ_BASE; 853 num_vqs = vscsi->num_queues + VIRTIO_SCSI_VQ_BASE;
925 vqs = kmalloc(num_vqs * sizeof(struct virtqueue *), GFP_KERNEL); 854 vqs = kmalloc(num_vqs * sizeof(struct virtqueue *), GFP_KERNEL);
@@ -942,7 +871,7 @@ static int virtscsi_init(struct virtio_device *vdev,
942 871
943 /* Discover virtqueues and write information to configuration. */ 872 /* Discover virtqueues and write information to configuration. */
944 err = vdev->config->find_vqs(vdev, num_vqs, vqs, callbacks, names, 873 err = vdev->config->find_vqs(vdev, num_vqs, vqs, callbacks, names,
945 NULL); 874 &desc);
946 if (err) 875 if (err)
947 goto out; 876 goto out;
948 877
@@ -1008,10 +937,6 @@ static int virtscsi_probe(struct virtio_device *vdev)
1008 if (err) 937 if (err)
1009 goto virtscsi_init_failed; 938 goto virtscsi_init_failed;
1010 939
1011 err = virtscsi_cpu_notif_add(vscsi);
1012 if (err)
1013 goto scsi_add_host_failed;
1014
1015 cmd_per_lun = virtscsi_config_get(vdev, cmd_per_lun) ?: 1; 940 cmd_per_lun = virtscsi_config_get(vdev, cmd_per_lun) ?: 1;
1016 shost->cmd_per_lun = min_t(u32, cmd_per_lun, shost->can_queue); 941 shost->cmd_per_lun = min_t(u32, cmd_per_lun, shost->can_queue);
1017 shost->max_sectors = virtscsi_config_get(vdev, max_sectors) ?: 0xFFFF; 942 shost->max_sectors = virtscsi_config_get(vdev, max_sectors) ?: 0xFFFF;
@@ -1066,9 +991,6 @@ static void virtscsi_remove(struct virtio_device *vdev)
1066 virtscsi_cancel_event_work(vscsi); 991 virtscsi_cancel_event_work(vscsi);
1067 992
1068 scsi_remove_host(shost); 993 scsi_remove_host(shost);
1069
1070 virtscsi_cpu_notif_remove(vscsi);
1071
1072 virtscsi_remove_vqs(vdev); 994 virtscsi_remove_vqs(vdev);
1073 scsi_host_put(shost); 995 scsi_host_put(shost);
1074} 996}
@@ -1076,10 +998,6 @@ static void virtscsi_remove(struct virtio_device *vdev)
1076#ifdef CONFIG_PM_SLEEP 998#ifdef CONFIG_PM_SLEEP
1077static int virtscsi_freeze(struct virtio_device *vdev) 999static int virtscsi_freeze(struct virtio_device *vdev)
1078{ 1000{
1079 struct Scsi_Host *sh = virtio_scsi_host(vdev);
1080 struct virtio_scsi *vscsi = shost_priv(sh);
1081
1082 virtscsi_cpu_notif_remove(vscsi);
1083 virtscsi_remove_vqs(vdev); 1001 virtscsi_remove_vqs(vdev);
1084 return 0; 1002 return 0;
1085} 1003}
@@ -1094,11 +1012,6 @@ static int virtscsi_restore(struct virtio_device *vdev)
1094 if (err) 1012 if (err)
1095 return err; 1013 return err;
1096 1014
1097 err = virtscsi_cpu_notif_add(vscsi);
1098 if (err) {
1099 vdev->config->del_vqs(vdev);
1100 return err;
1101 }
1102 virtio_device_ready(vdev); 1015 virtio_device_ready(vdev);
1103 1016
1104 if (virtio_has_feature(vdev, VIRTIO_SCSI_F_HOTPLUG)) 1017 if (virtio_has_feature(vdev, VIRTIO_SCSI_F_HOTPLUG))
@@ -1153,16 +1066,6 @@ static int __init init(void)
1153 pr_err("mempool_create() for virtscsi_cmd_pool failed\n"); 1066 pr_err("mempool_create() for virtscsi_cmd_pool failed\n");
1154 goto error; 1067 goto error;
1155 } 1068 }
1156 ret = cpuhp_setup_state_multi(CPUHP_AP_ONLINE_DYN,
1157 "scsi/virtio:online",
1158 virtscsi_cpu_online, NULL);
1159 if (ret < 0)
1160 goto error;
1161 virtioscsi_online = ret;
1162 ret = cpuhp_setup_state_multi(CPUHP_VIRT_SCSI_DEAD, "scsi/virtio:dead",
1163 NULL, virtscsi_cpu_online);
1164 if (ret)
1165 goto error;
1166 ret = register_virtio_driver(&virtio_scsi_driver); 1069 ret = register_virtio_driver(&virtio_scsi_driver);
1167 if (ret < 0) 1070 if (ret < 0)
1168 goto error; 1071 goto error;
@@ -1178,17 +1081,12 @@ error:
1178 kmem_cache_destroy(virtscsi_cmd_cache); 1081 kmem_cache_destroy(virtscsi_cmd_cache);
1179 virtscsi_cmd_cache = NULL; 1082 virtscsi_cmd_cache = NULL;
1180 } 1083 }
1181 if (virtioscsi_online)
1182 cpuhp_remove_multi_state(virtioscsi_online);
1183 cpuhp_remove_multi_state(CPUHP_VIRT_SCSI_DEAD);
1184 return ret; 1084 return ret;
1185} 1085}
1186 1086
1187static void __exit fini(void) 1087static void __exit fini(void)
1188{ 1088{
1189 unregister_virtio_driver(&virtio_scsi_driver); 1089 unregister_virtio_driver(&virtio_scsi_driver);
1190 cpuhp_remove_multi_state(virtioscsi_online);
1191 cpuhp_remove_multi_state(CPUHP_VIRT_SCSI_DEAD);
1192 mempool_destroy(virtscsi_cmd_pool); 1090 mempool_destroy(virtscsi_cmd_pool);
1193 kmem_cache_destroy(virtscsi_cmd_cache); 1091 kmem_cache_destroy(virtscsi_cmd_cache);
1194} 1092}
diff --git a/include/linux/cpuhotplug.h b/include/linux/cpuhotplug.h
index 921acaaa1601..01aea80a503e 100644
--- a/include/linux/cpuhotplug.h
+++ b/include/linux/cpuhotplug.h
@@ -26,7 +26,6 @@ enum cpuhp_state {
26 CPUHP_ARM_OMAP_WAKE_DEAD, 26 CPUHP_ARM_OMAP_WAKE_DEAD,
27 CPUHP_IRQ_POLL_DEAD, 27 CPUHP_IRQ_POLL_DEAD,
28 CPUHP_BLOCK_SOFTIRQ_DEAD, 28 CPUHP_BLOCK_SOFTIRQ_DEAD,
29 CPUHP_VIRT_SCSI_DEAD,
30 CPUHP_ACPI_CPUDRV_DEAD, 29 CPUHP_ACPI_CPUDRV_DEAD,
31 CPUHP_S390_PFAULT_DEAD, 30 CPUHP_S390_PFAULT_DEAD,
32 CPUHP_BLK_MQ_DEAD, 31 CPUHP_BLK_MQ_DEAD,