diff options
author | Bart Van Assche <bvanassche@acm.org> | 2010-11-26 13:22:48 -0500 |
---|---|---|
committer | David Dillow <dillowda@ornl.gov> | 2011-01-05 15:24:25 -0500 |
commit | dcb4cb85f4b7caac9769bce464fef16306a4758c (patch) | |
tree | 1c21889c8b778415f9a8d46fcf28853eb42ede18 /drivers/infiniband | |
parent | 9709f0e05b827049733f439de82a4a1688b37b86 (diff) |
IB/srp: allow lockless work posting
Only one CPU at a time will own an RX IU, so using the address of the IU
as the work request cookie allows us to avoid taking a lock. We can
similarly prepare the TX path for lockless posting by moving the free TX
IUs to a list. This also removes the requirement that the queue sizes be
a power of 2.
Signed-off-by: Bart Van Assche <bvanassche@acm.org>
[ broken out, small cleanups, and modified to avoid needing an extra field
in the IU by David Dillow]
Signed-off-by: David Dillow <dillowda@ornl.gov>
Diffstat (limited to 'drivers/infiniband')
-rw-r--r-- | drivers/infiniband/ulp/srp/ib_srp.c | 65 | ||||
-rw-r--r-- | drivers/infiniband/ulp/srp/ib_srp.h | 7 |
2 files changed, 28 insertions, 44 deletions
diff --git a/drivers/infiniband/ulp/srp/ib_srp.c b/drivers/infiniband/ulp/srp/ib_srp.c index def9e6b38459..aa78d2615c8d 100644 --- a/drivers/infiniband/ulp/srp/ib_srp.c +++ b/drivers/infiniband/ulp/srp/ib_srp.c | |||
@@ -568,7 +568,7 @@ static int srp_reconnect_target(struct srp_target_port *target) | |||
568 | struct ib_qp_attr qp_attr; | 568 | struct ib_qp_attr qp_attr; |
569 | struct srp_request *req, *tmp; | 569 | struct srp_request *req, *tmp; |
570 | struct ib_wc wc; | 570 | struct ib_wc wc; |
571 | int ret; | 571 | int i, ret; |
572 | 572 | ||
573 | if (!srp_change_state(target, SRP_TARGET_LIVE, SRP_TARGET_CONNECTING)) | 573 | if (!srp_change_state(target, SRP_TARGET_LIVE, SRP_TARGET_CONNECTING)) |
574 | return -EAGAIN; | 574 | return -EAGAIN; |
@@ -601,9 +601,9 @@ static int srp_reconnect_target(struct srp_target_port *target) | |||
601 | srp_reset_req(target, req); | 601 | srp_reset_req(target, req); |
602 | spin_unlock_irq(target->scsi_host->host_lock); | 602 | spin_unlock_irq(target->scsi_host->host_lock); |
603 | 603 | ||
604 | target->rx_head = 0; | 604 | list_del_init(&target->free_tx); |
605 | target->tx_head = 0; | 605 | for (i = 0; i < SRP_SQ_SIZE; ++i) |
606 | target->tx_tail = 0; | 606 | list_move(&target->tx_ring[i]->list, &target->free_tx); |
607 | 607 | ||
608 | target->qp_in_error = 0; | 608 | target->qp_in_error = 0; |
609 | ret = srp_connect_target(target); | 609 | ret = srp_connect_target(target); |
@@ -817,7 +817,7 @@ static int srp_map_data(struct scsi_cmnd *scmnd, struct srp_target_port *target, | |||
817 | 817 | ||
818 | /* | 818 | /* |
819 | * Must be called with target->scsi_host->host_lock held to protect | 819 | * Must be called with target->scsi_host->host_lock held to protect |
820 | * req_lim and tx_head. Lock cannot be dropped between call here and | 820 | * req_lim and free_tx. Lock cannot be dropped between call here and |
821 | * call to __srp_post_send(). | 821 | * call to __srp_post_send(). |
822 | * | 822 | * |
823 | * Note: | 823 | * Note: |
@@ -837,7 +837,7 @@ static struct srp_iu *__srp_get_tx_iu(struct srp_target_port *target, | |||
837 | 837 | ||
838 | srp_send_completion(target->send_cq, target); | 838 | srp_send_completion(target->send_cq, target); |
839 | 839 | ||
840 | if (target->tx_head - target->tx_tail >= SRP_SQ_SIZE) | 840 | if (list_empty(&target->free_tx)) |
841 | return NULL; | 841 | return NULL; |
842 | 842 | ||
843 | /* Initiator responses to target requests do not consume credits */ | 843 | /* Initiator responses to target requests do not consume credits */ |
@@ -846,14 +846,14 @@ static struct srp_iu *__srp_get_tx_iu(struct srp_target_port *target, | |||
846 | return NULL; | 846 | return NULL; |
847 | } | 847 | } |
848 | 848 | ||
849 | iu = target->tx_ring[target->tx_head & SRP_SQ_MASK]; | 849 | iu = list_first_entry(&target->free_tx, struct srp_iu, list); |
850 | iu->type = iu_type; | 850 | iu->type = iu_type; |
851 | return iu; | 851 | return iu; |
852 | } | 852 | } |
853 | 853 | ||
854 | /* | 854 | /* |
855 | * Must be called with target->scsi_host->host_lock held to protect | 855 | * Must be called with target->scsi_host->host_lock held to protect |
856 | * req_lim and tx_head. | 856 | * req_lim and free_tx. |
857 | */ | 857 | */ |
858 | static int __srp_post_send(struct srp_target_port *target, | 858 | static int __srp_post_send(struct srp_target_port *target, |
859 | struct srp_iu *iu, int len) | 859 | struct srp_iu *iu, int len) |
@@ -867,7 +867,7 @@ static int __srp_post_send(struct srp_target_port *target, | |||
867 | list.lkey = target->srp_host->srp_dev->mr->lkey; | 867 | list.lkey = target->srp_host->srp_dev->mr->lkey; |
868 | 868 | ||
869 | wr.next = NULL; | 869 | wr.next = NULL; |
870 | wr.wr_id = target->tx_head & SRP_SQ_MASK; | 870 | wr.wr_id = (uintptr_t) iu; |
871 | wr.sg_list = &list; | 871 | wr.sg_list = &list; |
872 | wr.num_sge = 1; | 872 | wr.num_sge = 1; |
873 | wr.opcode = IB_WR_SEND; | 873 | wr.opcode = IB_WR_SEND; |
@@ -876,7 +876,7 @@ static int __srp_post_send(struct srp_target_port *target, | |||
876 | ret = ib_post_send(target->qp, &wr, &bad_wr); | 876 | ret = ib_post_send(target->qp, &wr, &bad_wr); |
877 | 877 | ||
878 | if (!ret) { | 878 | if (!ret) { |
879 | ++target->tx_head; | 879 | list_del(&iu->list); |
880 | if (iu->type != SRP_IU_RSP) | 880 | if (iu->type != SRP_IU_RSP) |
881 | --target->req_lim; | 881 | --target->req_lim; |
882 | } | 882 | } |
@@ -884,36 +884,21 @@ static int __srp_post_send(struct srp_target_port *target, | |||
884 | return ret; | 884 | return ret; |
885 | } | 885 | } |
886 | 886 | ||
887 | static int srp_post_recv(struct srp_target_port *target) | 887 | static int srp_post_recv(struct srp_target_port *target, struct srp_iu *iu) |
888 | { | 888 | { |
889 | unsigned long flags; | ||
890 | struct srp_iu *iu; | ||
891 | struct ib_sge list; | ||
892 | struct ib_recv_wr wr, *bad_wr; | 889 | struct ib_recv_wr wr, *bad_wr; |
893 | unsigned int next; | 890 | struct ib_sge list; |
894 | int ret; | ||
895 | |||
896 | spin_lock_irqsave(target->scsi_host->host_lock, flags); | ||
897 | |||
898 | next = target->rx_head & SRP_RQ_MASK; | ||
899 | wr.wr_id = next; | ||
900 | iu = target->rx_ring[next]; | ||
901 | 891 | ||
902 | list.addr = iu->dma; | 892 | list.addr = iu->dma; |
903 | list.length = iu->size; | 893 | list.length = iu->size; |
904 | list.lkey = target->srp_host->srp_dev->mr->lkey; | 894 | list.lkey = target->srp_host->srp_dev->mr->lkey; |
905 | 895 | ||
906 | wr.next = NULL; | 896 | wr.next = NULL; |
897 | wr.wr_id = (uintptr_t) iu; | ||
907 | wr.sg_list = &list; | 898 | wr.sg_list = &list; |
908 | wr.num_sge = 1; | 899 | wr.num_sge = 1; |
909 | 900 | ||
910 | ret = ib_post_recv(target->qp, &wr, &bad_wr); | 901 | return ib_post_recv(target->qp, &wr, &bad_wr); |
911 | if (!ret) | ||
912 | ++target->rx_head; | ||
913 | |||
914 | spin_unlock_irqrestore(target->scsi_host->host_lock, flags); | ||
915 | |||
916 | return ret; | ||
917 | } | 902 | } |
918 | 903 | ||
919 | static void srp_process_rsp(struct srp_target_port *target, struct srp_rsp *rsp) | 904 | static void srp_process_rsp(struct srp_target_port *target, struct srp_rsp *rsp) |
@@ -1030,14 +1015,11 @@ static void srp_process_aer_req(struct srp_target_port *target, | |||
1030 | 1015 | ||
1031 | static void srp_handle_recv(struct srp_target_port *target, struct ib_wc *wc) | 1016 | static void srp_handle_recv(struct srp_target_port *target, struct ib_wc *wc) |
1032 | { | 1017 | { |
1033 | struct ib_device *dev; | 1018 | struct ib_device *dev = target->srp_host->srp_dev->dev; |
1034 | struct srp_iu *iu; | 1019 | struct srp_iu *iu = (struct srp_iu *) wc->wr_id; |
1035 | int res; | 1020 | int res; |
1036 | u8 opcode; | 1021 | u8 opcode; |
1037 | 1022 | ||
1038 | iu = target->rx_ring[wc->wr_id]; | ||
1039 | |||
1040 | dev = target->srp_host->srp_dev->dev; | ||
1041 | ib_dma_sync_single_for_cpu(dev, iu->dma, target->max_ti_iu_len, | 1023 | ib_dma_sync_single_for_cpu(dev, iu->dma, target->max_ti_iu_len, |
1042 | DMA_FROM_DEVICE); | 1024 | DMA_FROM_DEVICE); |
1043 | 1025 | ||
@@ -1078,7 +1060,7 @@ static void srp_handle_recv(struct srp_target_port *target, struct ib_wc *wc) | |||
1078 | ib_dma_sync_single_for_device(dev, iu->dma, target->max_ti_iu_len, | 1060 | ib_dma_sync_single_for_device(dev, iu->dma, target->max_ti_iu_len, |
1079 | DMA_FROM_DEVICE); | 1061 | DMA_FROM_DEVICE); |
1080 | 1062 | ||
1081 | res = srp_post_recv(target); | 1063 | res = srp_post_recv(target, iu); |
1082 | if (res != 0) | 1064 | if (res != 0) |
1083 | shost_printk(KERN_ERR, target->scsi_host, | 1065 | shost_printk(KERN_ERR, target->scsi_host, |
1084 | PFX "Recv failed with error code %d\n", res); | 1066 | PFX "Recv failed with error code %d\n", res); |
@@ -1107,6 +1089,7 @@ static void srp_send_completion(struct ib_cq *cq, void *target_ptr) | |||
1107 | { | 1089 | { |
1108 | struct srp_target_port *target = target_ptr; | 1090 | struct srp_target_port *target = target_ptr; |
1109 | struct ib_wc wc; | 1091 | struct ib_wc wc; |
1092 | struct srp_iu *iu; | ||
1110 | 1093 | ||
1111 | while (ib_poll_cq(cq, 1, &wc) > 0) { | 1094 | while (ib_poll_cq(cq, 1, &wc) > 0) { |
1112 | if (wc.status) { | 1095 | if (wc.status) { |
@@ -1117,7 +1100,8 @@ static void srp_send_completion(struct ib_cq *cq, void *target_ptr) | |||
1117 | break; | 1100 | break; |
1118 | } | 1101 | } |
1119 | 1102 | ||
1120 | ++target->tx_tail; | 1103 | iu = (struct srp_iu *) wc.wr_id; |
1104 | list_add(&iu->list, &target->free_tx); | ||
1121 | } | 1105 | } |
1122 | } | 1106 | } |
1123 | 1107 | ||
@@ -1212,6 +1196,8 @@ static int srp_alloc_iu_bufs(struct srp_target_port *target) | |||
1212 | GFP_KERNEL, DMA_TO_DEVICE); | 1196 | GFP_KERNEL, DMA_TO_DEVICE); |
1213 | if (!target->tx_ring[i]) | 1197 | if (!target->tx_ring[i]) |
1214 | goto err; | 1198 | goto err; |
1199 | |||
1200 | list_add(&target->tx_ring[i]->list, &target->free_tx); | ||
1215 | } | 1201 | } |
1216 | 1202 | ||
1217 | return 0; | 1203 | return 0; |
@@ -1373,7 +1359,8 @@ static int srp_cm_handler(struct ib_cm_id *cm_id, struct ib_cm_event *event) | |||
1373 | break; | 1359 | break; |
1374 | 1360 | ||
1375 | for (i = 0; i < SRP_RQ_SIZE; i++) { | 1361 | for (i = 0; i < SRP_RQ_SIZE; i++) { |
1376 | target->status = srp_post_recv(target); | 1362 | struct srp_iu *iu = target->rx_ring[i]; |
1363 | target->status = srp_post_recv(target, iu); | ||
1377 | if (target->status) | 1364 | if (target->status) |
1378 | break; | 1365 | break; |
1379 | } | 1366 | } |
@@ -1965,6 +1952,7 @@ static ssize_t srp_create_target(struct device *dev, | |||
1965 | target->scsi_host = target_host; | 1952 | target->scsi_host = target_host; |
1966 | target->srp_host = host; | 1953 | target->srp_host = host; |
1967 | 1954 | ||
1955 | INIT_LIST_HEAD(&target->free_tx); | ||
1968 | INIT_LIST_HEAD(&target->free_reqs); | 1956 | INIT_LIST_HEAD(&target->free_reqs); |
1969 | INIT_LIST_HEAD(&target->req_queue); | 1957 | INIT_LIST_HEAD(&target->req_queue); |
1970 | for (i = 0; i < SRP_CMD_SQ_SIZE; ++i) { | 1958 | for (i = 0; i < SRP_CMD_SQ_SIZE; ++i) { |
@@ -2235,8 +2223,7 @@ static int __init srp_init_module(void) | |||
2235 | { | 2223 | { |
2236 | int ret; | 2224 | int ret; |
2237 | 2225 | ||
2238 | BUILD_BUG_ON_NOT_POWER_OF_2(SRP_SQ_SIZE); | 2226 | BUILD_BUG_ON(FIELD_SIZEOF(struct ib_wc, wr_id) < sizeof(void *)); |
2239 | BUILD_BUG_ON_NOT_POWER_OF_2(SRP_RQ_SIZE); | ||
2240 | 2227 | ||
2241 | if (srp_sg_tablesize > 255) { | 2228 | if (srp_sg_tablesize > 255) { |
2242 | printk(KERN_WARNING PFX "Clamping srp_sg_tablesize to 255\n"); | 2229 | printk(KERN_WARNING PFX "Clamping srp_sg_tablesize to 255\n"); |
diff --git a/drivers/infiniband/ulp/srp/ib_srp.h b/drivers/infiniband/ulp/srp/ib_srp.h index f8b689a644b7..41ecb46adf15 100644 --- a/drivers/infiniband/ulp/srp/ib_srp.h +++ b/drivers/infiniband/ulp/srp/ib_srp.h | |||
@@ -59,10 +59,8 @@ enum { | |||
59 | 59 | ||
60 | SRP_RQ_SHIFT = 6, | 60 | SRP_RQ_SHIFT = 6, |
61 | SRP_RQ_SIZE = 1 << SRP_RQ_SHIFT, | 61 | SRP_RQ_SIZE = 1 << SRP_RQ_SHIFT, |
62 | SRP_RQ_MASK = SRP_RQ_SIZE - 1, | ||
63 | 62 | ||
64 | SRP_SQ_SIZE = SRP_RQ_SIZE, | 63 | SRP_SQ_SIZE = SRP_RQ_SIZE, |
65 | SRP_SQ_MASK = SRP_SQ_SIZE - 1, | ||
66 | SRP_RSP_SQ_SIZE = 1, | 64 | SRP_RSP_SQ_SIZE = 1, |
67 | SRP_REQ_SQ_SIZE = SRP_SQ_SIZE - SRP_RSP_SQ_SIZE, | 65 | SRP_REQ_SQ_SIZE = SRP_SQ_SIZE - SRP_RSP_SQ_SIZE, |
68 | SRP_TSK_MGMT_SQ_SIZE = 1, | 66 | SRP_TSK_MGMT_SQ_SIZE = 1, |
@@ -144,11 +142,9 @@ struct srp_target_port { | |||
144 | 142 | ||
145 | int zero_req_lim; | 143 | int zero_req_lim; |
146 | 144 | ||
147 | unsigned rx_head; | ||
148 | struct srp_iu *rx_ring[SRP_RQ_SIZE]; | 145 | struct srp_iu *rx_ring[SRP_RQ_SIZE]; |
149 | 146 | ||
150 | unsigned tx_head; | 147 | struct list_head free_tx; |
151 | unsigned tx_tail; | ||
152 | struct srp_iu *tx_ring[SRP_SQ_SIZE]; | 148 | struct srp_iu *tx_ring[SRP_SQ_SIZE]; |
153 | 149 | ||
154 | struct list_head free_reqs; | 150 | struct list_head free_reqs; |
@@ -168,6 +164,7 @@ struct srp_target_port { | |||
168 | }; | 164 | }; |
169 | 165 | ||
170 | struct srp_iu { | 166 | struct srp_iu { |
167 | struct list_head list; | ||
171 | u64 dma; | 168 | u64 dma; |
172 | void *buf; | 169 | void *buf; |
173 | size_t size; | 170 | size_t size; |