diff options
author | Jack Morgenstein <jackm@mellanox.co.il> | 2006-03-04 00:54:13 -0500 |
---|---|---|
committer | Roland Dreier <rolandd@cisco.com> | 2006-03-20 13:08:23 -0500 |
commit | f36e1793e25513380cae5958a9164d4cc4458ad0 (patch) | |
tree | aa31d34ee07971645af6f21068709166420caee2 /drivers/infiniband/core | |
parent | 6ecb0c849625e830ab96495d473bb704812c30e1 (diff) |
IB/umad: Add support for large RMPP transfers
Add support for sending and receiving large RMPP transfers. The old
code supports transfers only as large as a single contiguous kernel
memory allocation. This patch uses linked list of memory buffers when
sending and receiving data to avoid needing contiguous pages for
larger transfers.
Receive side: copy the arriving MADs in chunks instead of coalescing
to one large buffer in kernel space.
Send side: split a multipacket MAD buffer to a list of segments,
(multipacket_list) and send these using a gather list of size 2.
Also, save pointer to last sent segment, and retrieve requested
segments by walking list starting at last sent segment. Finally,
save pointer to last-acked segment. When retrying, retrieve
segments for resending relative to this pointer. When updating last
ack, start at this pointer.
Signed-off-by: Jack Morgenstein <jackm@mellanox.co.il>
Signed-off-by: Sean Hefty <sean.hefty@intel.com>
Signed-off-by: Roland Dreier <rolandd@cisco.com>
Diffstat (limited to 'drivers/infiniband/core')
-rw-r--r-- | drivers/infiniband/core/mad.c | 166 | ||||
-rw-r--r-- | drivers/infiniband/core/mad_priv.h | 16 | ||||
-rw-r--r-- | drivers/infiniband/core/mad_rmpp.c | 148 | ||||
-rw-r--r-- | drivers/infiniband/core/user_mad.c | 225 |
4 files changed, 346 insertions, 209 deletions
diff --git a/drivers/infiniband/core/mad.c b/drivers/infiniband/core/mad.c index 445ad0dda213..16549add8e8f 100644 --- a/drivers/infiniband/core/mad.c +++ b/drivers/infiniband/core/mad.c | |||
@@ -31,7 +31,7 @@ | |||
31 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | 31 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE |
32 | * SOFTWARE. | 32 | * SOFTWARE. |
33 | * | 33 | * |
34 | * $Id: mad.c 2817 2005-07-07 11:29:26Z halr $ | 34 | * $Id: mad.c 5596 2006-03-03 01:00:07Z sean.hefty $ |
35 | */ | 35 | */ |
36 | #include <linux/dma-mapping.h> | 36 | #include <linux/dma-mapping.h> |
37 | 37 | ||
@@ -765,18 +765,67 @@ out: | |||
765 | return ret; | 765 | return ret; |
766 | } | 766 | } |
767 | 767 | ||
768 | static int get_buf_length(int hdr_len, int data_len) | 768 | static int get_pad_size(int hdr_len, int data_len) |
769 | { | 769 | { |
770 | int seg_size, pad; | 770 | int seg_size, pad; |
771 | 771 | ||
772 | seg_size = sizeof(struct ib_mad) - hdr_len; | 772 | seg_size = sizeof(struct ib_mad) - hdr_len; |
773 | if (data_len && seg_size) { | 773 | if (data_len && seg_size) { |
774 | pad = seg_size - data_len % seg_size; | 774 | pad = seg_size - data_len % seg_size; |
775 | if (pad == seg_size) | 775 | return pad == seg_size ? 0 : pad; |
776 | pad = 0; | ||
777 | } else | 776 | } else |
778 | pad = seg_size; | 777 | return seg_size; |
779 | return hdr_len + data_len + pad; | 778 | } |
779 | |||
780 | static void free_send_rmpp_list(struct ib_mad_send_wr_private *mad_send_wr) | ||
781 | { | ||
782 | struct ib_rmpp_segment *s, *t; | ||
783 | |||
784 | list_for_each_entry_safe(s, t, &mad_send_wr->rmpp_list, list) { | ||
785 | list_del(&s->list); | ||
786 | kfree(s); | ||
787 | } | ||
788 | } | ||
789 | |||
790 | static int alloc_send_rmpp_list(struct ib_mad_send_wr_private *send_wr, | ||
791 | gfp_t gfp_mask) | ||
792 | { | ||
793 | struct ib_mad_send_buf *send_buf = &send_wr->send_buf; | ||
794 | struct ib_rmpp_mad *rmpp_mad = send_buf->mad; | ||
795 | struct ib_rmpp_segment *seg = NULL; | ||
796 | int left, seg_size, pad; | ||
797 | |||
798 | send_buf->seg_size = sizeof (struct ib_mad) - send_buf->hdr_len; | ||
799 | seg_size = send_buf->seg_size; | ||
800 | pad = send_wr->pad; | ||
801 | |||
802 | /* Allocate data segments. */ | ||
803 | for (left = send_buf->data_len + pad; left > 0; left -= seg_size) { | ||
804 | seg = kmalloc(sizeof (*seg) + seg_size, gfp_mask); | ||
805 | if (!seg) { | ||
806 | printk(KERN_ERR "alloc_send_rmpp_segs: RMPP mem " | ||
807 | "alloc failed for len %zd, gfp %#x\n", | ||
808 | sizeof (*seg) + seg_size, gfp_mask); | ||
809 | free_send_rmpp_list(send_wr); | ||
810 | return -ENOMEM; | ||
811 | } | ||
812 | seg->num = ++send_buf->seg_count; | ||
813 | list_add_tail(&seg->list, &send_wr->rmpp_list); | ||
814 | } | ||
815 | |||
816 | /* Zero any padding */ | ||
817 | if (pad) | ||
818 | memset(seg->data + seg_size - pad, 0, pad); | ||
819 | |||
820 | rmpp_mad->rmpp_hdr.rmpp_version = send_wr->mad_agent_priv-> | ||
821 | agent.rmpp_version; | ||
822 | rmpp_mad->rmpp_hdr.rmpp_type = IB_MGMT_RMPP_TYPE_DATA; | ||
823 | ib_set_rmpp_flags(&rmpp_mad->rmpp_hdr, IB_MGMT_RMPP_FLAG_ACTIVE); | ||
824 | |||
825 | send_wr->cur_seg = container_of(send_wr->rmpp_list.next, | ||
826 | struct ib_rmpp_segment, list); | ||
827 | send_wr->last_ack_seg = send_wr->cur_seg; | ||
828 | return 0; | ||
780 | } | 829 | } |
781 | 830 | ||
782 | struct ib_mad_send_buf * ib_create_send_mad(struct ib_mad_agent *mad_agent, | 831 | struct ib_mad_send_buf * ib_create_send_mad(struct ib_mad_agent *mad_agent, |
@@ -787,32 +836,40 @@ struct ib_mad_send_buf * ib_create_send_mad(struct ib_mad_agent *mad_agent, | |||
787 | { | 836 | { |
788 | struct ib_mad_agent_private *mad_agent_priv; | 837 | struct ib_mad_agent_private *mad_agent_priv; |
789 | struct ib_mad_send_wr_private *mad_send_wr; | 838 | struct ib_mad_send_wr_private *mad_send_wr; |
790 | int buf_size; | 839 | int pad, message_size, ret, size; |
791 | void *buf; | 840 | void *buf; |
792 | 841 | ||
793 | mad_agent_priv = container_of(mad_agent, struct ib_mad_agent_private, | 842 | mad_agent_priv = container_of(mad_agent, struct ib_mad_agent_private, |
794 | agent); | 843 | agent); |
795 | buf_size = get_buf_length(hdr_len, data_len); | 844 | pad = get_pad_size(hdr_len, data_len); |
845 | message_size = hdr_len + data_len + pad; | ||
796 | 846 | ||
797 | if ((!mad_agent->rmpp_version && | 847 | if ((!mad_agent->rmpp_version && |
798 | (rmpp_active || buf_size > sizeof(struct ib_mad))) || | 848 | (rmpp_active || message_size > sizeof(struct ib_mad))) || |
799 | (!rmpp_active && buf_size > sizeof(struct ib_mad))) | 849 | (!rmpp_active && message_size > sizeof(struct ib_mad))) |
800 | return ERR_PTR(-EINVAL); | 850 | return ERR_PTR(-EINVAL); |
801 | 851 | ||
802 | buf = kzalloc(sizeof *mad_send_wr + buf_size, gfp_mask); | 852 | size = rmpp_active ? hdr_len : sizeof(struct ib_mad); |
853 | buf = kzalloc(sizeof *mad_send_wr + size, gfp_mask); | ||
803 | if (!buf) | 854 | if (!buf) |
804 | return ERR_PTR(-ENOMEM); | 855 | return ERR_PTR(-ENOMEM); |
805 | 856 | ||
806 | mad_send_wr = buf + buf_size; | 857 | mad_send_wr = buf + size; |
858 | INIT_LIST_HEAD(&mad_send_wr->rmpp_list); | ||
807 | mad_send_wr->send_buf.mad = buf; | 859 | mad_send_wr->send_buf.mad = buf; |
860 | mad_send_wr->send_buf.hdr_len = hdr_len; | ||
861 | mad_send_wr->send_buf.data_len = data_len; | ||
862 | mad_send_wr->pad = pad; | ||
808 | 863 | ||
809 | mad_send_wr->mad_agent_priv = mad_agent_priv; | 864 | mad_send_wr->mad_agent_priv = mad_agent_priv; |
810 | mad_send_wr->sg_list[0].length = buf_size; | 865 | mad_send_wr->sg_list[0].length = hdr_len; |
811 | mad_send_wr->sg_list[0].lkey = mad_agent->mr->lkey; | 866 | mad_send_wr->sg_list[0].lkey = mad_agent->mr->lkey; |
867 | mad_send_wr->sg_list[1].length = sizeof(struct ib_mad) - hdr_len; | ||
868 | mad_send_wr->sg_list[1].lkey = mad_agent->mr->lkey; | ||
812 | 869 | ||
813 | mad_send_wr->send_wr.wr_id = (unsigned long) mad_send_wr; | 870 | mad_send_wr->send_wr.wr_id = (unsigned long) mad_send_wr; |
814 | mad_send_wr->send_wr.sg_list = mad_send_wr->sg_list; | 871 | mad_send_wr->send_wr.sg_list = mad_send_wr->sg_list; |
815 | mad_send_wr->send_wr.num_sge = 1; | 872 | mad_send_wr->send_wr.num_sge = 2; |
816 | mad_send_wr->send_wr.opcode = IB_WR_SEND; | 873 | mad_send_wr->send_wr.opcode = IB_WR_SEND; |
817 | mad_send_wr->send_wr.send_flags = IB_SEND_SIGNALED; | 874 | mad_send_wr->send_wr.send_flags = IB_SEND_SIGNALED; |
818 | mad_send_wr->send_wr.wr.ud.remote_qpn = remote_qpn; | 875 | mad_send_wr->send_wr.wr.ud.remote_qpn = remote_qpn; |
@@ -820,13 +877,11 @@ struct ib_mad_send_buf * ib_create_send_mad(struct ib_mad_agent *mad_agent, | |||
820 | mad_send_wr->send_wr.wr.ud.pkey_index = pkey_index; | 877 | mad_send_wr->send_wr.wr.ud.pkey_index = pkey_index; |
821 | 878 | ||
822 | if (rmpp_active) { | 879 | if (rmpp_active) { |
823 | struct ib_rmpp_mad *rmpp_mad = mad_send_wr->send_buf.mad; | 880 | ret = alloc_send_rmpp_list(mad_send_wr, gfp_mask); |
824 | rmpp_mad->rmpp_hdr.paylen_newwin = cpu_to_be32(hdr_len - | 881 | if (ret) { |
825 | IB_MGMT_RMPP_HDR + data_len); | 882 | kfree(buf); |
826 | rmpp_mad->rmpp_hdr.rmpp_version = mad_agent->rmpp_version; | 883 | return ERR_PTR(ret); |
827 | rmpp_mad->rmpp_hdr.rmpp_type = IB_MGMT_RMPP_TYPE_DATA; | 884 | } |
828 | ib_set_rmpp_flags(&rmpp_mad->rmpp_hdr, | ||
829 | IB_MGMT_RMPP_FLAG_ACTIVE); | ||
830 | } | 885 | } |
831 | 886 | ||
832 | mad_send_wr->send_buf.mad_agent = mad_agent; | 887 | mad_send_wr->send_buf.mad_agent = mad_agent; |
@@ -835,14 +890,50 @@ struct ib_mad_send_buf * ib_create_send_mad(struct ib_mad_agent *mad_agent, | |||
835 | } | 890 | } |
836 | EXPORT_SYMBOL(ib_create_send_mad); | 891 | EXPORT_SYMBOL(ib_create_send_mad); |
837 | 892 | ||
893 | void *ib_get_rmpp_segment(struct ib_mad_send_buf *send_buf, int seg_num) | ||
894 | { | ||
895 | struct ib_mad_send_wr_private *mad_send_wr; | ||
896 | struct list_head *list; | ||
897 | |||
898 | mad_send_wr = container_of(send_buf, struct ib_mad_send_wr_private, | ||
899 | send_buf); | ||
900 | list = &mad_send_wr->cur_seg->list; | ||
901 | |||
902 | if (mad_send_wr->cur_seg->num < seg_num) { | ||
903 | list_for_each_entry(mad_send_wr->cur_seg, list, list) | ||
904 | if (mad_send_wr->cur_seg->num == seg_num) | ||
905 | break; | ||
906 | } else if (mad_send_wr->cur_seg->num > seg_num) { | ||
907 | list_for_each_entry_reverse(mad_send_wr->cur_seg, list, list) | ||
908 | if (mad_send_wr->cur_seg->num == seg_num) | ||
909 | break; | ||
910 | } | ||
911 | return mad_send_wr->cur_seg->data; | ||
912 | } | ||
913 | EXPORT_SYMBOL(ib_get_rmpp_segment); | ||
914 | |||
915 | static inline void *ib_get_payload(struct ib_mad_send_wr_private *mad_send_wr) | ||
916 | { | ||
917 | if (mad_send_wr->send_buf.seg_count) | ||
918 | return ib_get_rmpp_segment(&mad_send_wr->send_buf, | ||
919 | mad_send_wr->seg_num); | ||
920 | else | ||
921 | return mad_send_wr->send_buf.mad + | ||
922 | mad_send_wr->send_buf.hdr_len; | ||
923 | } | ||
924 | |||
838 | void ib_free_send_mad(struct ib_mad_send_buf *send_buf) | 925 | void ib_free_send_mad(struct ib_mad_send_buf *send_buf) |
839 | { | 926 | { |
840 | struct ib_mad_agent_private *mad_agent_priv; | 927 | struct ib_mad_agent_private *mad_agent_priv; |
928 | struct ib_mad_send_wr_private *mad_send_wr; | ||
841 | 929 | ||
842 | mad_agent_priv = container_of(send_buf->mad_agent, | 930 | mad_agent_priv = container_of(send_buf->mad_agent, |
843 | struct ib_mad_agent_private, agent); | 931 | struct ib_mad_agent_private, agent); |
844 | kfree(send_buf->mad); | 932 | mad_send_wr = container_of(send_buf, struct ib_mad_send_wr_private, |
933 | send_buf); | ||
845 | 934 | ||
935 | free_send_rmpp_list(mad_send_wr); | ||
936 | kfree(send_buf->mad); | ||
846 | if (atomic_dec_and_test(&mad_agent_priv->refcount)) | 937 | if (atomic_dec_and_test(&mad_agent_priv->refcount)) |
847 | wake_up(&mad_agent_priv->wait); | 938 | wake_up(&mad_agent_priv->wait); |
848 | } | 939 | } |
@@ -865,10 +956,17 @@ int ib_send_mad(struct ib_mad_send_wr_private *mad_send_wr) | |||
865 | 956 | ||
866 | mad_agent = mad_send_wr->send_buf.mad_agent; | 957 | mad_agent = mad_send_wr->send_buf.mad_agent; |
867 | sge = mad_send_wr->sg_list; | 958 | sge = mad_send_wr->sg_list; |
868 | sge->addr = dma_map_single(mad_agent->device->dma_device, | 959 | sge[0].addr = dma_map_single(mad_agent->device->dma_device, |
869 | mad_send_wr->send_buf.mad, sge->length, | 960 | mad_send_wr->send_buf.mad, |
870 | DMA_TO_DEVICE); | 961 | sge[0].length, |
871 | pci_unmap_addr_set(mad_send_wr, mapping, sge->addr); | 962 | DMA_TO_DEVICE); |
963 | pci_unmap_addr_set(mad_send_wr, header_mapping, sge[0].addr); | ||
964 | |||
965 | sge[1].addr = dma_map_single(mad_agent->device->dma_device, | ||
966 | ib_get_payload(mad_send_wr), | ||
967 | sge[1].length, | ||
968 | DMA_TO_DEVICE); | ||
969 | pci_unmap_addr_set(mad_send_wr, payload_mapping, sge[1].addr); | ||
872 | 970 | ||
873 | spin_lock_irqsave(&qp_info->send_queue.lock, flags); | 971 | spin_lock_irqsave(&qp_info->send_queue.lock, flags); |
874 | if (qp_info->send_queue.count < qp_info->send_queue.max_active) { | 972 | if (qp_info->send_queue.count < qp_info->send_queue.max_active) { |
@@ -885,11 +983,14 @@ int ib_send_mad(struct ib_mad_send_wr_private *mad_send_wr) | |||
885 | list_add_tail(&mad_send_wr->mad_list.list, list); | 983 | list_add_tail(&mad_send_wr->mad_list.list, list); |
886 | } | 984 | } |
887 | spin_unlock_irqrestore(&qp_info->send_queue.lock, flags); | 985 | spin_unlock_irqrestore(&qp_info->send_queue.lock, flags); |
888 | if (ret) | 986 | if (ret) { |
889 | dma_unmap_single(mad_agent->device->dma_device, | 987 | dma_unmap_single(mad_agent->device->dma_device, |
890 | pci_unmap_addr(mad_send_wr, mapping), | 988 | pci_unmap_addr(mad_send_wr, header_mapping), |
891 | sge->length, DMA_TO_DEVICE); | 989 | sge[0].length, DMA_TO_DEVICE); |
892 | 990 | dma_unmap_single(mad_agent->device->dma_device, | |
991 | pci_unmap_addr(mad_send_wr, payload_mapping), | ||
992 | sge[1].length, DMA_TO_DEVICE); | ||
993 | } | ||
893 | return ret; | 994 | return ret; |
894 | } | 995 | } |
895 | 996 | ||
@@ -1860,8 +1961,11 @@ static void ib_mad_send_done_handler(struct ib_mad_port_private *port_priv, | |||
1860 | 1961 | ||
1861 | retry: | 1962 | retry: |
1862 | dma_unmap_single(mad_send_wr->send_buf.mad_agent->device->dma_device, | 1963 | dma_unmap_single(mad_send_wr->send_buf.mad_agent->device->dma_device, |
1863 | pci_unmap_addr(mad_send_wr, mapping), | 1964 | pci_unmap_addr(mad_send_wr, header_mapping), |
1864 | mad_send_wr->sg_list[0].length, DMA_TO_DEVICE); | 1965 | mad_send_wr->sg_list[0].length, DMA_TO_DEVICE); |
1966 | dma_unmap_single(mad_send_wr->send_buf.mad_agent->device->dma_device, | ||
1967 | pci_unmap_addr(mad_send_wr, payload_mapping), | ||
1968 | mad_send_wr->sg_list[1].length, DMA_TO_DEVICE); | ||
1865 | queued_send_wr = NULL; | 1969 | queued_send_wr = NULL; |
1866 | spin_lock_irqsave(&send_queue->lock, flags); | 1970 | spin_lock_irqsave(&send_queue->lock, flags); |
1867 | list_del(&mad_list->list); | 1971 | list_del(&mad_list->list); |
diff --git a/drivers/infiniband/core/mad_priv.h b/drivers/infiniband/core/mad_priv.h index 570f78682af3..a7125d4b5ccf 100644 --- a/drivers/infiniband/core/mad_priv.h +++ b/drivers/infiniband/core/mad_priv.h | |||
@@ -31,7 +31,7 @@ | |||
31 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | 31 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE |
32 | * SOFTWARE. | 32 | * SOFTWARE. |
33 | * | 33 | * |
34 | * $Id: mad_priv.h 2730 2005-06-28 16:43:03Z sean.hefty $ | 34 | * $Id: mad_priv.h 5596 2006-03-03 01:00:07Z sean.hefty $ |
35 | */ | 35 | */ |
36 | 36 | ||
37 | #ifndef __IB_MAD_PRIV_H__ | 37 | #ifndef __IB_MAD_PRIV_H__ |
@@ -85,6 +85,12 @@ struct ib_mad_private { | |||
85 | } mad; | 85 | } mad; |
86 | } __attribute__ ((packed)); | 86 | } __attribute__ ((packed)); |
87 | 87 | ||
88 | struct ib_rmpp_segment { | ||
89 | struct list_head list; | ||
90 | u32 num; | ||
91 | u8 data[0]; | ||
92 | }; | ||
93 | |||
88 | struct ib_mad_agent_private { | 94 | struct ib_mad_agent_private { |
89 | struct list_head agent_list; | 95 | struct list_head agent_list; |
90 | struct ib_mad_agent agent; | 96 | struct ib_mad_agent agent; |
@@ -119,7 +125,8 @@ struct ib_mad_send_wr_private { | |||
119 | struct list_head agent_list; | 125 | struct list_head agent_list; |
120 | struct ib_mad_agent_private *mad_agent_priv; | 126 | struct ib_mad_agent_private *mad_agent_priv; |
121 | struct ib_mad_send_buf send_buf; | 127 | struct ib_mad_send_buf send_buf; |
122 | DECLARE_PCI_UNMAP_ADDR(mapping) | 128 | DECLARE_PCI_UNMAP_ADDR(header_mapping) |
129 | DECLARE_PCI_UNMAP_ADDR(payload_mapping) | ||
123 | struct ib_send_wr send_wr; | 130 | struct ib_send_wr send_wr; |
124 | struct ib_sge sg_list[IB_MAD_SEND_REQ_MAX_SG]; | 131 | struct ib_sge sg_list[IB_MAD_SEND_REQ_MAX_SG]; |
125 | __be64 tid; | 132 | __be64 tid; |
@@ -130,11 +137,12 @@ struct ib_mad_send_wr_private { | |||
130 | enum ib_wc_status status; | 137 | enum ib_wc_status status; |
131 | 138 | ||
132 | /* RMPP control */ | 139 | /* RMPP control */ |
140 | struct list_head rmpp_list; | ||
141 | struct ib_rmpp_segment *last_ack_seg; | ||
142 | struct ib_rmpp_segment *cur_seg; | ||
133 | int last_ack; | 143 | int last_ack; |
134 | int seg_num; | 144 | int seg_num; |
135 | int newwin; | 145 | int newwin; |
136 | int total_seg; | ||
137 | int data_offset; | ||
138 | int pad; | 146 | int pad; |
139 | }; | 147 | }; |
140 | 148 | ||
diff --git a/drivers/infiniband/core/mad_rmpp.c b/drivers/infiniband/core/mad_rmpp.c index 3249e1d8c07b..bacfdd5bddad 100644 --- a/drivers/infiniband/core/mad_rmpp.c +++ b/drivers/infiniband/core/mad_rmpp.c | |||
@@ -111,14 +111,14 @@ static int data_offset(u8 mgmt_class) | |||
111 | return IB_MGMT_RMPP_HDR; | 111 | return IB_MGMT_RMPP_HDR; |
112 | } | 112 | } |
113 | 113 | ||
114 | static void format_ack(struct ib_rmpp_mad *ack, | 114 | static void format_ack(struct ib_mad_send_buf *msg, |
115 | struct ib_rmpp_mad *data, | 115 | struct ib_rmpp_mad *data, |
116 | struct mad_rmpp_recv *rmpp_recv) | 116 | struct mad_rmpp_recv *rmpp_recv) |
117 | { | 117 | { |
118 | struct ib_rmpp_mad *ack = msg->mad; | ||
118 | unsigned long flags; | 119 | unsigned long flags; |
119 | 120 | ||
120 | memcpy(&ack->mad_hdr, &data->mad_hdr, | 121 | memcpy(ack, &data->mad_hdr, msg->hdr_len); |
121 | data_offset(data->mad_hdr.mgmt_class)); | ||
122 | 122 | ||
123 | ack->mad_hdr.method ^= IB_MGMT_METHOD_RESP; | 123 | ack->mad_hdr.method ^= IB_MGMT_METHOD_RESP; |
124 | ack->rmpp_hdr.rmpp_type = IB_MGMT_RMPP_TYPE_ACK; | 124 | ack->rmpp_hdr.rmpp_type = IB_MGMT_RMPP_TYPE_ACK; |
@@ -135,16 +135,16 @@ static void ack_recv(struct mad_rmpp_recv *rmpp_recv, | |||
135 | struct ib_mad_recv_wc *recv_wc) | 135 | struct ib_mad_recv_wc *recv_wc) |
136 | { | 136 | { |
137 | struct ib_mad_send_buf *msg; | 137 | struct ib_mad_send_buf *msg; |
138 | int ret; | 138 | int ret, hdr_len; |
139 | 139 | ||
140 | hdr_len = data_offset(recv_wc->recv_buf.mad->mad_hdr.mgmt_class); | ||
140 | msg = ib_create_send_mad(&rmpp_recv->agent->agent, recv_wc->wc->src_qp, | 141 | msg = ib_create_send_mad(&rmpp_recv->agent->agent, recv_wc->wc->src_qp, |
141 | recv_wc->wc->pkey_index, 1, IB_MGMT_RMPP_HDR, | 142 | recv_wc->wc->pkey_index, 1, hdr_len, |
142 | IB_MGMT_RMPP_DATA, GFP_KERNEL); | 143 | 0, GFP_KERNEL); |
143 | if (!msg) | 144 | if (!msg) |
144 | return; | 145 | return; |
145 | 146 | ||
146 | format_ack(msg->mad, (struct ib_rmpp_mad *) recv_wc->recv_buf.mad, | 147 | format_ack(msg, (struct ib_rmpp_mad *) recv_wc->recv_buf.mad, rmpp_recv); |
147 | rmpp_recv); | ||
148 | msg->ah = rmpp_recv->ah; | 148 | msg->ah = rmpp_recv->ah; |
149 | ret = ib_post_send_mad(msg, NULL); | 149 | ret = ib_post_send_mad(msg, NULL); |
150 | if (ret) | 150 | if (ret) |
@@ -156,16 +156,17 @@ static struct ib_mad_send_buf *alloc_response_msg(struct ib_mad_agent *agent, | |||
156 | { | 156 | { |
157 | struct ib_mad_send_buf *msg; | 157 | struct ib_mad_send_buf *msg; |
158 | struct ib_ah *ah; | 158 | struct ib_ah *ah; |
159 | int hdr_len; | ||
159 | 160 | ||
160 | ah = ib_create_ah_from_wc(agent->qp->pd, recv_wc->wc, | 161 | ah = ib_create_ah_from_wc(agent->qp->pd, recv_wc->wc, |
161 | recv_wc->recv_buf.grh, agent->port_num); | 162 | recv_wc->recv_buf.grh, agent->port_num); |
162 | if (IS_ERR(ah)) | 163 | if (IS_ERR(ah)) |
163 | return (void *) ah; | 164 | return (void *) ah; |
164 | 165 | ||
166 | hdr_len = data_offset(recv_wc->recv_buf.mad->mad_hdr.mgmt_class); | ||
165 | msg = ib_create_send_mad(agent, recv_wc->wc->src_qp, | 167 | msg = ib_create_send_mad(agent, recv_wc->wc->src_qp, |
166 | recv_wc->wc->pkey_index, 1, | 168 | recv_wc->wc->pkey_index, 1, |
167 | IB_MGMT_RMPP_HDR, IB_MGMT_RMPP_DATA, | 169 | hdr_len, 0, GFP_KERNEL); |
168 | GFP_KERNEL); | ||
169 | if (IS_ERR(msg)) | 170 | if (IS_ERR(msg)) |
170 | ib_destroy_ah(ah); | 171 | ib_destroy_ah(ah); |
171 | else | 172 | else |
@@ -195,8 +196,7 @@ static void nack_recv(struct ib_mad_agent_private *agent, | |||
195 | return; | 196 | return; |
196 | 197 | ||
197 | rmpp_mad = msg->mad; | 198 | rmpp_mad = msg->mad; |
198 | memcpy(rmpp_mad, recv_wc->recv_buf.mad, | 199 | memcpy(rmpp_mad, recv_wc->recv_buf.mad, msg->hdr_len); |
199 | data_offset(recv_wc->recv_buf.mad->mad_hdr.mgmt_class)); | ||
200 | 200 | ||
201 | rmpp_mad->mad_hdr.method ^= IB_MGMT_METHOD_RESP; | 201 | rmpp_mad->mad_hdr.method ^= IB_MGMT_METHOD_RESP; |
202 | rmpp_mad->rmpp_hdr.rmpp_version = IB_MGMT_RMPP_VERSION; | 202 | rmpp_mad->rmpp_hdr.rmpp_version = IB_MGMT_RMPP_VERSION; |
@@ -433,44 +433,6 @@ static struct ib_mad_recv_wc * complete_rmpp(struct mad_rmpp_recv *rmpp_recv) | |||
433 | return rmpp_wc; | 433 | return rmpp_wc; |
434 | } | 434 | } |
435 | 435 | ||
436 | void ib_coalesce_recv_mad(struct ib_mad_recv_wc *mad_recv_wc, void *buf) | ||
437 | { | ||
438 | struct ib_mad_recv_buf *seg_buf; | ||
439 | struct ib_rmpp_mad *rmpp_mad; | ||
440 | void *data; | ||
441 | int size, len, offset; | ||
442 | u8 flags; | ||
443 | |||
444 | len = mad_recv_wc->mad_len; | ||
445 | if (len <= sizeof(struct ib_mad)) { | ||
446 | memcpy(buf, mad_recv_wc->recv_buf.mad, len); | ||
447 | return; | ||
448 | } | ||
449 | |||
450 | offset = data_offset(mad_recv_wc->recv_buf.mad->mad_hdr.mgmt_class); | ||
451 | |||
452 | list_for_each_entry(seg_buf, &mad_recv_wc->rmpp_list, list) { | ||
453 | rmpp_mad = (struct ib_rmpp_mad *)seg_buf->mad; | ||
454 | flags = ib_get_rmpp_flags(&rmpp_mad->rmpp_hdr); | ||
455 | |||
456 | if (flags & IB_MGMT_RMPP_FLAG_FIRST) { | ||
457 | data = rmpp_mad; | ||
458 | size = sizeof(*rmpp_mad); | ||
459 | } else { | ||
460 | data = (void *) rmpp_mad + offset; | ||
461 | if (flags & IB_MGMT_RMPP_FLAG_LAST) | ||
462 | size = len; | ||
463 | else | ||
464 | size = sizeof(*rmpp_mad) - offset; | ||
465 | } | ||
466 | |||
467 | memcpy(buf, data, size); | ||
468 | len -= size; | ||
469 | buf += size; | ||
470 | } | ||
471 | } | ||
472 | EXPORT_SYMBOL(ib_coalesce_recv_mad); | ||
473 | |||
474 | static struct ib_mad_recv_wc * | 436 | static struct ib_mad_recv_wc * |
475 | continue_rmpp(struct ib_mad_agent_private *agent, | 437 | continue_rmpp(struct ib_mad_agent_private *agent, |
476 | struct ib_mad_recv_wc *mad_recv_wc) | 438 | struct ib_mad_recv_wc *mad_recv_wc) |
@@ -570,50 +532,33 @@ start_rmpp(struct ib_mad_agent_private *agent, | |||
570 | return mad_recv_wc; | 532 | return mad_recv_wc; |
571 | } | 533 | } |
572 | 534 | ||
573 | static inline u64 get_seg_addr(struct ib_mad_send_wr_private *mad_send_wr) | ||
574 | { | ||
575 | return mad_send_wr->sg_list[0].addr + mad_send_wr->data_offset + | ||
576 | (sizeof(struct ib_rmpp_mad) - mad_send_wr->data_offset) * | ||
577 | (mad_send_wr->seg_num - 1); | ||
578 | } | ||
579 | |||
580 | static int send_next_seg(struct ib_mad_send_wr_private *mad_send_wr) | 535 | static int send_next_seg(struct ib_mad_send_wr_private *mad_send_wr) |
581 | { | 536 | { |
582 | struct ib_rmpp_mad *rmpp_mad; | 537 | struct ib_rmpp_mad *rmpp_mad; |
583 | int timeout; | 538 | int timeout; |
584 | u32 paylen; | 539 | u32 paylen = 0; |
585 | 540 | ||
586 | rmpp_mad = mad_send_wr->send_buf.mad; | 541 | rmpp_mad = mad_send_wr->send_buf.mad; |
587 | ib_set_rmpp_flags(&rmpp_mad->rmpp_hdr, IB_MGMT_RMPP_FLAG_ACTIVE); | 542 | ib_set_rmpp_flags(&rmpp_mad->rmpp_hdr, IB_MGMT_RMPP_FLAG_ACTIVE); |
588 | rmpp_mad->rmpp_hdr.seg_num = cpu_to_be32(mad_send_wr->seg_num); | 543 | rmpp_mad->rmpp_hdr.seg_num = cpu_to_be32(++mad_send_wr->seg_num); |
589 | 544 | ||
590 | if (mad_send_wr->seg_num == 1) { | 545 | if (mad_send_wr->seg_num == 1) { |
591 | rmpp_mad->rmpp_hdr.rmpp_rtime_flags |= IB_MGMT_RMPP_FLAG_FIRST; | 546 | rmpp_mad->rmpp_hdr.rmpp_rtime_flags |= IB_MGMT_RMPP_FLAG_FIRST; |
592 | paylen = mad_send_wr->total_seg * IB_MGMT_RMPP_DATA - | 547 | paylen = mad_send_wr->send_buf.seg_count * IB_MGMT_RMPP_DATA - |
593 | mad_send_wr->pad; | 548 | mad_send_wr->pad; |
594 | rmpp_mad->rmpp_hdr.paylen_newwin = cpu_to_be32(paylen); | ||
595 | mad_send_wr->sg_list[0].length = sizeof(struct ib_rmpp_mad); | ||
596 | } else { | ||
597 | mad_send_wr->send_wr.num_sge = 2; | ||
598 | mad_send_wr->sg_list[0].length = mad_send_wr->data_offset; | ||
599 | mad_send_wr->sg_list[1].addr = get_seg_addr(mad_send_wr); | ||
600 | mad_send_wr->sg_list[1].length = sizeof(struct ib_rmpp_mad) - | ||
601 | mad_send_wr->data_offset; | ||
602 | mad_send_wr->sg_list[1].lkey = mad_send_wr->sg_list[0].lkey; | ||
603 | rmpp_mad->rmpp_hdr.paylen_newwin = 0; | ||
604 | } | 549 | } |
605 | 550 | ||
606 | if (mad_send_wr->seg_num == mad_send_wr->total_seg) { | 551 | if (mad_send_wr->seg_num == mad_send_wr->send_buf.seg_count) { |
607 | rmpp_mad->rmpp_hdr.rmpp_rtime_flags |= IB_MGMT_RMPP_FLAG_LAST; | 552 | rmpp_mad->rmpp_hdr.rmpp_rtime_flags |= IB_MGMT_RMPP_FLAG_LAST; |
608 | paylen = IB_MGMT_RMPP_DATA - mad_send_wr->pad; | 553 | paylen = IB_MGMT_RMPP_DATA - mad_send_wr->pad; |
609 | rmpp_mad->rmpp_hdr.paylen_newwin = cpu_to_be32(paylen); | ||
610 | } | 554 | } |
555 | rmpp_mad->rmpp_hdr.paylen_newwin = cpu_to_be32(paylen); | ||
611 | 556 | ||
612 | /* 2 seconds for an ACK until we can find the packet lifetime */ | 557 | /* 2 seconds for an ACK until we can find the packet lifetime */ |
613 | timeout = mad_send_wr->send_buf.timeout_ms; | 558 | timeout = mad_send_wr->send_buf.timeout_ms; |
614 | if (!timeout || timeout > 2000) | 559 | if (!timeout || timeout > 2000) |
615 | mad_send_wr->timeout = msecs_to_jiffies(2000); | 560 | mad_send_wr->timeout = msecs_to_jiffies(2000); |
616 | mad_send_wr->seg_num++; | 561 | |
617 | return ib_send_mad(mad_send_wr); | 562 | return ib_send_mad(mad_send_wr); |
618 | } | 563 | } |
619 | 564 | ||
@@ -629,7 +574,7 @@ static void abort_send(struct ib_mad_agent_private *agent, __be64 tid, | |||
629 | if (!mad_send_wr) | 574 | if (!mad_send_wr) |
630 | goto out; /* Unmatched send */ | 575 | goto out; /* Unmatched send */ |
631 | 576 | ||
632 | if ((mad_send_wr->last_ack == mad_send_wr->total_seg) || | 577 | if ((mad_send_wr->last_ack == mad_send_wr->send_buf.seg_count) || |
633 | (!mad_send_wr->timeout) || (mad_send_wr->status != IB_WC_SUCCESS)) | 578 | (!mad_send_wr->timeout) || (mad_send_wr->status != IB_WC_SUCCESS)) |
634 | goto out; /* Send is already done */ | 579 | goto out; /* Send is already done */ |
635 | 580 | ||
@@ -645,6 +590,18 @@ out: | |||
645 | spin_unlock_irqrestore(&agent->lock, flags); | 590 | spin_unlock_irqrestore(&agent->lock, flags); |
646 | } | 591 | } |
647 | 592 | ||
593 | static inline void adjust_last_ack(struct ib_mad_send_wr_private *wr, | ||
594 | int seg_num) | ||
595 | { | ||
596 | struct list_head *list; | ||
597 | |||
598 | wr->last_ack = seg_num; | ||
599 | list = &wr->last_ack_seg->list; | ||
600 | list_for_each_entry(wr->last_ack_seg, list, list) | ||
601 | if (wr->last_ack_seg->num == seg_num) | ||
602 | break; | ||
603 | } | ||
604 | |||
648 | static void process_rmpp_ack(struct ib_mad_agent_private *agent, | 605 | static void process_rmpp_ack(struct ib_mad_agent_private *agent, |
649 | struct ib_mad_recv_wc *mad_recv_wc) | 606 | struct ib_mad_recv_wc *mad_recv_wc) |
650 | { | 607 | { |
@@ -675,11 +632,12 @@ static void process_rmpp_ack(struct ib_mad_agent_private *agent, | |||
675 | if (!mad_send_wr) | 632 | if (!mad_send_wr) |
676 | goto out; /* Unmatched ACK */ | 633 | goto out; /* Unmatched ACK */ |
677 | 634 | ||
678 | if ((mad_send_wr->last_ack == mad_send_wr->total_seg) || | 635 | if ((mad_send_wr->last_ack == mad_send_wr->send_buf.seg_count) || |
679 | (!mad_send_wr->timeout) || (mad_send_wr->status != IB_WC_SUCCESS)) | 636 | (!mad_send_wr->timeout) || (mad_send_wr->status != IB_WC_SUCCESS)) |
680 | goto out; /* Send is already done */ | 637 | goto out; /* Send is already done */ |
681 | 638 | ||
682 | if (seg_num > mad_send_wr->total_seg || seg_num > mad_send_wr->newwin) { | 639 | if (seg_num > mad_send_wr->send_buf.seg_count || |
640 | seg_num > mad_send_wr->newwin) { | ||
683 | spin_unlock_irqrestore(&agent->lock, flags); | 641 | spin_unlock_irqrestore(&agent->lock, flags); |
684 | abort_send(agent, rmpp_mad->mad_hdr.tid, | 642 | abort_send(agent, rmpp_mad->mad_hdr.tid, |
685 | IB_MGMT_RMPP_STATUS_S2B); | 643 | IB_MGMT_RMPP_STATUS_S2B); |
@@ -691,11 +649,11 @@ static void process_rmpp_ack(struct ib_mad_agent_private *agent, | |||
691 | goto out; /* Old ACK */ | 649 | goto out; /* Old ACK */ |
692 | 650 | ||
693 | if (seg_num > mad_send_wr->last_ack) { | 651 | if (seg_num > mad_send_wr->last_ack) { |
694 | mad_send_wr->last_ack = seg_num; | 652 | adjust_last_ack(mad_send_wr, seg_num); |
695 | mad_send_wr->retries = mad_send_wr->send_buf.retries; | 653 | mad_send_wr->retries = mad_send_wr->send_buf.retries; |
696 | } | 654 | } |
697 | mad_send_wr->newwin = newwin; | 655 | mad_send_wr->newwin = newwin; |
698 | if (mad_send_wr->last_ack == mad_send_wr->total_seg) { | 656 | if (mad_send_wr->last_ack == mad_send_wr->send_buf.seg_count) { |
699 | /* If no response is expected, the ACK completes the send */ | 657 | /* If no response is expected, the ACK completes the send */ |
700 | if (!mad_send_wr->send_buf.timeout_ms) { | 658 | if (!mad_send_wr->send_buf.timeout_ms) { |
701 | struct ib_mad_send_wc wc; | 659 | struct ib_mad_send_wc wc; |
@@ -714,7 +672,7 @@ static void process_rmpp_ack(struct ib_mad_agent_private *agent, | |||
714 | mad_send_wr->send_buf.timeout_ms); | 672 | mad_send_wr->send_buf.timeout_ms); |
715 | } else if (mad_send_wr->refcount == 1 && | 673 | } else if (mad_send_wr->refcount == 1 && |
716 | mad_send_wr->seg_num < mad_send_wr->newwin && | 674 | mad_send_wr->seg_num < mad_send_wr->newwin && |
717 | mad_send_wr->seg_num <= mad_send_wr->total_seg) { | 675 | mad_send_wr->seg_num < mad_send_wr->send_buf.seg_count) { |
718 | /* Send failure will just result in a timeout/retry */ | 676 | /* Send failure will just result in a timeout/retry */ |
719 | ret = send_next_seg(mad_send_wr); | 677 | ret = send_next_seg(mad_send_wr); |
720 | if (ret) | 678 | if (ret) |
@@ -838,31 +796,19 @@ out: | |||
838 | int ib_send_rmpp_mad(struct ib_mad_send_wr_private *mad_send_wr) | 796 | int ib_send_rmpp_mad(struct ib_mad_send_wr_private *mad_send_wr) |
839 | { | 797 | { |
840 | struct ib_rmpp_mad *rmpp_mad; | 798 | struct ib_rmpp_mad *rmpp_mad; |
841 | int i, total_len, ret; | 799 | int ret; |
842 | 800 | ||
843 | rmpp_mad = mad_send_wr->send_buf.mad; | 801 | rmpp_mad = mad_send_wr->send_buf.mad; |
844 | if (!(ib_get_rmpp_flags(&rmpp_mad->rmpp_hdr) & | 802 | if (!(ib_get_rmpp_flags(&rmpp_mad->rmpp_hdr) & |
845 | IB_MGMT_RMPP_FLAG_ACTIVE)) | 803 | IB_MGMT_RMPP_FLAG_ACTIVE)) |
846 | return IB_RMPP_RESULT_UNHANDLED; | 804 | return IB_RMPP_RESULT_UNHANDLED; |
847 | 805 | ||
848 | if (rmpp_mad->rmpp_hdr.rmpp_type != IB_MGMT_RMPP_TYPE_DATA) | 806 | if (rmpp_mad->rmpp_hdr.rmpp_type != IB_MGMT_RMPP_TYPE_DATA) { |
807 | mad_send_wr->seg_num = 1; | ||
849 | return IB_RMPP_RESULT_INTERNAL; | 808 | return IB_RMPP_RESULT_INTERNAL; |
809 | } | ||
850 | 810 | ||
851 | if (mad_send_wr->send_wr.num_sge > 1) | ||
852 | return -EINVAL; /* TODO: support num_sge > 1 */ | ||
853 | |||
854 | mad_send_wr->seg_num = 1; | ||
855 | mad_send_wr->newwin = 1; | 811 | mad_send_wr->newwin = 1; |
856 | mad_send_wr->data_offset = data_offset(rmpp_mad->mad_hdr.mgmt_class); | ||
857 | |||
858 | total_len = 0; | ||
859 | for (i = 0; i < mad_send_wr->send_wr.num_sge; i++) | ||
860 | total_len += mad_send_wr->send_wr.sg_list[i].length; | ||
861 | |||
862 | mad_send_wr->total_seg = (total_len - mad_send_wr->data_offset) / | ||
863 | (sizeof(struct ib_rmpp_mad) - mad_send_wr->data_offset); | ||
864 | mad_send_wr->pad = total_len - IB_MGMT_RMPP_HDR - | ||
865 | be32_to_cpu(rmpp_mad->rmpp_hdr.paylen_newwin); | ||
866 | 812 | ||
867 | /* We need to wait for the final ACK even if there isn't a response */ | 813 | /* We need to wait for the final ACK even if there isn't a response */ |
868 | mad_send_wr->refcount += (mad_send_wr->timeout == 0); | 814 | mad_send_wr->refcount += (mad_send_wr->timeout == 0); |
@@ -893,14 +839,14 @@ int ib_process_rmpp_send_wc(struct ib_mad_send_wr_private *mad_send_wr, | |||
893 | if (!mad_send_wr->timeout) | 839 | if (!mad_send_wr->timeout) |
894 | return IB_RMPP_RESULT_PROCESSED; /* Response received */ | 840 | return IB_RMPP_RESULT_PROCESSED; /* Response received */ |
895 | 841 | ||
896 | if (mad_send_wr->last_ack == mad_send_wr->total_seg) { | 842 | if (mad_send_wr->last_ack == mad_send_wr->send_buf.seg_count) { |
897 | mad_send_wr->timeout = | 843 | mad_send_wr->timeout = |
898 | msecs_to_jiffies(mad_send_wr->send_buf.timeout_ms); | 844 | msecs_to_jiffies(mad_send_wr->send_buf.timeout_ms); |
899 | return IB_RMPP_RESULT_PROCESSED; /* Send done */ | 845 | return IB_RMPP_RESULT_PROCESSED; /* Send done */ |
900 | } | 846 | } |
901 | 847 | ||
902 | if (mad_send_wr->seg_num > mad_send_wr->newwin || | 848 | if (mad_send_wr->seg_num == mad_send_wr->newwin || |
903 | mad_send_wr->seg_num > mad_send_wr->total_seg) | 849 | mad_send_wr->seg_num == mad_send_wr->send_buf.seg_count) |
904 | return IB_RMPP_RESULT_PROCESSED; /* Wait for ACK */ | 850 | return IB_RMPP_RESULT_PROCESSED; /* Wait for ACK */ |
905 | 851 | ||
906 | ret = send_next_seg(mad_send_wr); | 852 | ret = send_next_seg(mad_send_wr); |
@@ -921,10 +867,12 @@ int ib_retry_rmpp(struct ib_mad_send_wr_private *mad_send_wr) | |||
921 | IB_MGMT_RMPP_FLAG_ACTIVE)) | 867 | IB_MGMT_RMPP_FLAG_ACTIVE)) |
922 | return IB_RMPP_RESULT_UNHANDLED; /* RMPP not active */ | 868 | return IB_RMPP_RESULT_UNHANDLED; /* RMPP not active */ |
923 | 869 | ||
924 | if (mad_send_wr->last_ack == mad_send_wr->total_seg) | 870 | if (mad_send_wr->last_ack == mad_send_wr->send_buf.seg_count) |
925 | return IB_RMPP_RESULT_PROCESSED; | 871 | return IB_RMPP_RESULT_PROCESSED; |
926 | 872 | ||
927 | mad_send_wr->seg_num = mad_send_wr->last_ack + 1; | 873 | mad_send_wr->seg_num = mad_send_wr->last_ack; |
874 | mad_send_wr->cur_seg = mad_send_wr->last_ack_seg; | ||
875 | |||
928 | ret = send_next_seg(mad_send_wr); | 876 | ret = send_next_seg(mad_send_wr); |
929 | if (ret) | 877 | if (ret) |
930 | return IB_RMPP_RESULT_PROCESSED; | 878 | return IB_RMPP_RESULT_PROCESSED; |
diff --git a/drivers/infiniband/core/user_mad.c b/drivers/infiniband/core/user_mad.c index c908de8db5a9..fb6cd42601f9 100644 --- a/drivers/infiniband/core/user_mad.c +++ b/drivers/infiniband/core/user_mad.c | |||
@@ -31,7 +31,7 @@ | |||
31 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | 31 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE |
32 | * SOFTWARE. | 32 | * SOFTWARE. |
33 | * | 33 | * |
34 | * $Id: user_mad.c 4010 2005-11-09 23:11:56Z roland $ | 34 | * $Id: user_mad.c 5596 2006-03-03 01:00:07Z sean.hefty $ |
35 | */ | 35 | */ |
36 | 36 | ||
37 | #include <linux/module.h> | 37 | #include <linux/module.h> |
@@ -121,6 +121,7 @@ struct ib_umad_file { | |||
121 | 121 | ||
122 | struct ib_umad_packet { | 122 | struct ib_umad_packet { |
123 | struct ib_mad_send_buf *msg; | 123 | struct ib_mad_send_buf *msg; |
124 | struct ib_mad_recv_wc *recv_wc; | ||
124 | struct list_head list; | 125 | struct list_head list; |
125 | int length; | 126 | int length; |
126 | struct ib_user_mad mad; | 127 | struct ib_user_mad mad; |
@@ -176,31 +177,32 @@ static int queue_packet(struct ib_umad_file *file, | |||
176 | return ret; | 177 | return ret; |
177 | } | 178 | } |
178 | 179 | ||
180 | static int data_offset(u8 mgmt_class) | ||
181 | { | ||
182 | if (mgmt_class == IB_MGMT_CLASS_SUBN_ADM) | ||
183 | return IB_MGMT_SA_HDR; | ||
184 | else if ((mgmt_class >= IB_MGMT_CLASS_VENDOR_RANGE2_START) && | ||
185 | (mgmt_class <= IB_MGMT_CLASS_VENDOR_RANGE2_END)) | ||
186 | return IB_MGMT_VENDOR_HDR; | ||
187 | else | ||
188 | return IB_MGMT_RMPP_HDR; | ||
189 | } | ||
190 | |||
179 | static void send_handler(struct ib_mad_agent *agent, | 191 | static void send_handler(struct ib_mad_agent *agent, |
180 | struct ib_mad_send_wc *send_wc) | 192 | struct ib_mad_send_wc *send_wc) |
181 | { | 193 | { |
182 | struct ib_umad_file *file = agent->context; | 194 | struct ib_umad_file *file = agent->context; |
183 | struct ib_umad_packet *timeout; | ||
184 | struct ib_umad_packet *packet = send_wc->send_buf->context[0]; | 195 | struct ib_umad_packet *packet = send_wc->send_buf->context[0]; |
185 | 196 | ||
186 | ib_destroy_ah(packet->msg->ah); | 197 | ib_destroy_ah(packet->msg->ah); |
187 | ib_free_send_mad(packet->msg); | 198 | ib_free_send_mad(packet->msg); |
188 | 199 | ||
189 | if (send_wc->status == IB_WC_RESP_TIMEOUT_ERR) { | 200 | if (send_wc->status == IB_WC_RESP_TIMEOUT_ERR) { |
190 | timeout = kzalloc(sizeof *timeout + IB_MGMT_MAD_HDR, GFP_KERNEL); | 201 | packet->length = IB_MGMT_MAD_HDR; |
191 | if (!timeout) | 202 | packet->mad.hdr.status = ETIMEDOUT; |
192 | goto out; | 203 | if (!queue_packet(file, agent, packet)) |
193 | 204 | return; | |
194 | timeout->length = IB_MGMT_MAD_HDR; | ||
195 | timeout->mad.hdr.id = packet->mad.hdr.id; | ||
196 | timeout->mad.hdr.status = ETIMEDOUT; | ||
197 | memcpy(timeout->mad.data, packet->mad.data, | ||
198 | sizeof (struct ib_mad_hdr)); | ||
199 | |||
200 | if (queue_packet(file, agent, timeout)) | ||
201 | kfree(timeout); | ||
202 | } | 205 | } |
203 | out: | ||
204 | kfree(packet); | 206 | kfree(packet); |
205 | } | 207 | } |
206 | 208 | ||
@@ -209,22 +211,20 @@ static void recv_handler(struct ib_mad_agent *agent, | |||
209 | { | 211 | { |
210 | struct ib_umad_file *file = agent->context; | 212 | struct ib_umad_file *file = agent->context; |
211 | struct ib_umad_packet *packet; | 213 | struct ib_umad_packet *packet; |
212 | int length; | ||
213 | 214 | ||
214 | if (mad_recv_wc->wc->status != IB_WC_SUCCESS) | 215 | if (mad_recv_wc->wc->status != IB_WC_SUCCESS) |
215 | goto out; | 216 | goto err1; |
216 | 217 | ||
217 | length = mad_recv_wc->mad_len; | 218 | packet = kzalloc(sizeof *packet, GFP_KERNEL); |
218 | packet = kzalloc(sizeof *packet + length, GFP_KERNEL); | ||
219 | if (!packet) | 219 | if (!packet) |
220 | goto out; | 220 | goto err1; |
221 | 221 | ||
222 | packet->length = length; | 222 | packet->length = mad_recv_wc->mad_len; |
223 | 223 | packet->recv_wc = mad_recv_wc; | |
224 | ib_coalesce_recv_mad(mad_recv_wc, packet->mad.data); | ||
225 | 224 | ||
226 | packet->mad.hdr.status = 0; | 225 | packet->mad.hdr.status = 0; |
227 | packet->mad.hdr.length = length + sizeof (struct ib_user_mad); | 226 | packet->mad.hdr.length = sizeof (struct ib_user_mad) + |
227 | mad_recv_wc->mad_len; | ||
228 | packet->mad.hdr.qpn = cpu_to_be32(mad_recv_wc->wc->src_qp); | 228 | packet->mad.hdr.qpn = cpu_to_be32(mad_recv_wc->wc->src_qp); |
229 | packet->mad.hdr.lid = cpu_to_be16(mad_recv_wc->wc->slid); | 229 | packet->mad.hdr.lid = cpu_to_be16(mad_recv_wc->wc->slid); |
230 | packet->mad.hdr.sl = mad_recv_wc->wc->sl; | 230 | packet->mad.hdr.sl = mad_recv_wc->wc->sl; |
@@ -240,12 +240,79 @@ static void recv_handler(struct ib_mad_agent *agent, | |||
240 | } | 240 | } |
241 | 241 | ||
242 | if (queue_packet(file, agent, packet)) | 242 | if (queue_packet(file, agent, packet)) |
243 | kfree(packet); | 243 | goto err2; |
244 | return; | ||
244 | 245 | ||
245 | out: | 246 | err2: |
247 | kfree(packet); | ||
248 | err1: | ||
246 | ib_free_recv_mad(mad_recv_wc); | 249 | ib_free_recv_mad(mad_recv_wc); |
247 | } | 250 | } |
248 | 251 | ||
252 | static ssize_t copy_recv_mad(char __user *buf, struct ib_umad_packet *packet, | ||
253 | size_t count) | ||
254 | { | ||
255 | struct ib_mad_recv_buf *recv_buf; | ||
256 | int left, seg_payload, offset, max_seg_payload; | ||
257 | |||
258 | /* We need enough room to copy the first (or only) MAD segment. */ | ||
259 | recv_buf = &packet->recv_wc->recv_buf; | ||
260 | if ((packet->length <= sizeof (*recv_buf->mad) && | ||
261 | count < sizeof (packet->mad) + packet->length) || | ||
262 | (packet->length > sizeof (*recv_buf->mad) && | ||
263 | count < sizeof (packet->mad) + sizeof (*recv_buf->mad))) | ||
264 | return -EINVAL; | ||
265 | |||
266 | if (copy_to_user(buf, &packet->mad, sizeof (packet->mad))) | ||
267 | return -EFAULT; | ||
268 | |||
269 | buf += sizeof (packet->mad); | ||
270 | seg_payload = min_t(int, packet->length, sizeof (*recv_buf->mad)); | ||
271 | if (copy_to_user(buf, recv_buf->mad, seg_payload)) | ||
272 | return -EFAULT; | ||
273 | |||
274 | if (seg_payload < packet->length) { | ||
275 | /* | ||
276 | * Multipacket RMPP MAD message. Copy remainder of message. | ||
277 | * Note that last segment may have a shorter payload. | ||
278 | */ | ||
279 | if (count < sizeof (packet->mad) + packet->length) { | ||
280 | /* | ||
281 | * The buffer is too small, return the first RMPP segment, | ||
282 | * which includes the RMPP message length. | ||
283 | */ | ||
284 | return -ENOSPC; | ||
285 | } | ||
286 | offset = data_offset(recv_buf->mad->mad_hdr.mgmt_class); | ||
287 | max_seg_payload = sizeof (struct ib_mad) - offset; | ||
288 | |||
289 | for (left = packet->length - seg_payload, buf += seg_payload; | ||
290 | left; left -= seg_payload, buf += seg_payload) { | ||
291 | recv_buf = container_of(recv_buf->list.next, | ||
292 | struct ib_mad_recv_buf, list); | ||
293 | seg_payload = min(left, max_seg_payload); | ||
294 | if (copy_to_user(buf, ((void *) recv_buf->mad) + offset, | ||
295 | seg_payload)) | ||
296 | return -EFAULT; | ||
297 | } | ||
298 | } | ||
299 | return sizeof (packet->mad) + packet->length; | ||
300 | } | ||
301 | |||
302 | static ssize_t copy_send_mad(char __user *buf, struct ib_umad_packet *packet, | ||
303 | size_t count) | ||
304 | { | ||
305 | ssize_t size = sizeof (packet->mad) + packet->length; | ||
306 | |||
307 | if (count < size) | ||
308 | return -EINVAL; | ||
309 | |||
310 | if (copy_to_user(buf, &packet->mad, size)) | ||
311 | return -EFAULT; | ||
312 | |||
313 | return size; | ||
314 | } | ||
315 | |||
249 | static ssize_t ib_umad_read(struct file *filp, char __user *buf, | 316 | static ssize_t ib_umad_read(struct file *filp, char __user *buf, |
250 | size_t count, loff_t *pos) | 317 | size_t count, loff_t *pos) |
251 | { | 318 | { |
@@ -253,7 +320,7 @@ static ssize_t ib_umad_read(struct file *filp, char __user *buf, | |||
253 | struct ib_umad_packet *packet; | 320 | struct ib_umad_packet *packet; |
254 | ssize_t ret; | 321 | ssize_t ret; |
255 | 322 | ||
256 | if (count < sizeof (struct ib_user_mad) + sizeof (struct ib_mad)) | 323 | if (count < sizeof (struct ib_user_mad)) |
257 | return -EINVAL; | 324 | return -EINVAL; |
258 | 325 | ||
259 | spin_lock_irq(&file->recv_lock); | 326 | spin_lock_irq(&file->recv_lock); |
@@ -276,28 +343,44 @@ static ssize_t ib_umad_read(struct file *filp, char __user *buf, | |||
276 | 343 | ||
277 | spin_unlock_irq(&file->recv_lock); | 344 | spin_unlock_irq(&file->recv_lock); |
278 | 345 | ||
279 | if (count < packet->length + sizeof (struct ib_user_mad)) { | 346 | if (packet->recv_wc) |
280 | /* Return length needed (and first RMPP segment) if too small */ | 347 | ret = copy_recv_mad(buf, packet, count); |
281 | if (copy_to_user(buf, &packet->mad, | ||
282 | sizeof (struct ib_user_mad) + sizeof (struct ib_mad))) | ||
283 | ret = -EFAULT; | ||
284 | else | ||
285 | ret = -ENOSPC; | ||
286 | } else if (copy_to_user(buf, &packet->mad, | ||
287 | packet->length + sizeof (struct ib_user_mad))) | ||
288 | ret = -EFAULT; | ||
289 | else | 348 | else |
290 | ret = packet->length + sizeof (struct ib_user_mad); | 349 | ret = copy_send_mad(buf, packet, count); |
350 | |||
291 | if (ret < 0) { | 351 | if (ret < 0) { |
292 | /* Requeue packet */ | 352 | /* Requeue packet */ |
293 | spin_lock_irq(&file->recv_lock); | 353 | spin_lock_irq(&file->recv_lock); |
294 | list_add(&packet->list, &file->recv_list); | 354 | list_add(&packet->list, &file->recv_list); |
295 | spin_unlock_irq(&file->recv_lock); | 355 | spin_unlock_irq(&file->recv_lock); |
296 | } else | 356 | } else { |
357 | if (packet->recv_wc) | ||
358 | ib_free_recv_mad(packet->recv_wc); | ||
297 | kfree(packet); | 359 | kfree(packet); |
360 | } | ||
298 | return ret; | 361 | return ret; |
299 | } | 362 | } |
300 | 363 | ||
364 | static int copy_rmpp_mad(struct ib_mad_send_buf *msg, const char __user *buf) | ||
365 | { | ||
366 | int left, seg; | ||
367 | |||
368 | /* Copy class specific header */ | ||
369 | if ((msg->hdr_len > IB_MGMT_RMPP_HDR) && | ||
370 | copy_from_user(msg->mad + IB_MGMT_RMPP_HDR, buf + IB_MGMT_RMPP_HDR, | ||
371 | msg->hdr_len - IB_MGMT_RMPP_HDR)) | ||
372 | return -EFAULT; | ||
373 | |||
374 | /* All headers are in place. Copy data segments. */ | ||
375 | for (seg = 1, left = msg->data_len, buf += msg->hdr_len; left > 0; | ||
376 | seg++, left -= msg->seg_size, buf += msg->seg_size) { | ||
377 | if (copy_from_user(ib_get_rmpp_segment(msg, seg), buf, | ||
378 | min(left, msg->seg_size))) | ||
379 | return -EFAULT; | ||
380 | } | ||
381 | return 0; | ||
382 | } | ||
383 | |||
301 | static ssize_t ib_umad_write(struct file *filp, const char __user *buf, | 384 | static ssize_t ib_umad_write(struct file *filp, const char __user *buf, |
302 | size_t count, loff_t *pos) | 385 | size_t count, loff_t *pos) |
303 | { | 386 | { |
@@ -309,14 +392,12 @@ static ssize_t ib_umad_write(struct file *filp, const char __user *buf, | |||
309 | struct ib_rmpp_mad *rmpp_mad; | 392 | struct ib_rmpp_mad *rmpp_mad; |
310 | u8 method; | 393 | u8 method; |
311 | __be64 *tid; | 394 | __be64 *tid; |
312 | int ret, length, hdr_len, copy_offset; | 395 | int ret, data_len, hdr_len, copy_offset, rmpp_active; |
313 | int rmpp_active, has_rmpp_header; | ||
314 | 396 | ||
315 | if (count < sizeof (struct ib_user_mad) + IB_MGMT_RMPP_HDR) | 397 | if (count < sizeof (struct ib_user_mad) + IB_MGMT_RMPP_HDR) |
316 | return -EINVAL; | 398 | return -EINVAL; |
317 | 399 | ||
318 | length = count - sizeof (struct ib_user_mad); | 400 | packet = kzalloc(sizeof *packet + IB_MGMT_RMPP_HDR, GFP_KERNEL); |
319 | packet = kmalloc(sizeof *packet + IB_MGMT_RMPP_HDR, GFP_KERNEL); | ||
320 | if (!packet) | 401 | if (!packet) |
321 | return -ENOMEM; | 402 | return -ENOMEM; |
322 | 403 | ||
@@ -363,35 +444,25 @@ static ssize_t ib_umad_write(struct file *filp, const char __user *buf, | |||
363 | if (rmpp_mad->mad_hdr.mgmt_class == IB_MGMT_CLASS_SUBN_ADM) { | 444 | if (rmpp_mad->mad_hdr.mgmt_class == IB_MGMT_CLASS_SUBN_ADM) { |
364 | hdr_len = IB_MGMT_SA_HDR; | 445 | hdr_len = IB_MGMT_SA_HDR; |
365 | copy_offset = IB_MGMT_RMPP_HDR; | 446 | copy_offset = IB_MGMT_RMPP_HDR; |
366 | has_rmpp_header = 1; | 447 | rmpp_active = ib_get_rmpp_flags(&rmpp_mad->rmpp_hdr) & |
448 | IB_MGMT_RMPP_FLAG_ACTIVE; | ||
367 | } else if (rmpp_mad->mad_hdr.mgmt_class >= IB_MGMT_CLASS_VENDOR_RANGE2_START && | 449 | } else if (rmpp_mad->mad_hdr.mgmt_class >= IB_MGMT_CLASS_VENDOR_RANGE2_START && |
368 | rmpp_mad->mad_hdr.mgmt_class <= IB_MGMT_CLASS_VENDOR_RANGE2_END) { | 450 | rmpp_mad->mad_hdr.mgmt_class <= IB_MGMT_CLASS_VENDOR_RANGE2_END) { |
369 | hdr_len = IB_MGMT_VENDOR_HDR; | 451 | hdr_len = IB_MGMT_VENDOR_HDR; |
370 | copy_offset = IB_MGMT_RMPP_HDR; | 452 | copy_offset = IB_MGMT_RMPP_HDR; |
371 | has_rmpp_header = 1; | 453 | rmpp_active = ib_get_rmpp_flags(&rmpp_mad->rmpp_hdr) & |
454 | IB_MGMT_RMPP_FLAG_ACTIVE; | ||
372 | } else { | 455 | } else { |
373 | hdr_len = IB_MGMT_MAD_HDR; | 456 | hdr_len = IB_MGMT_MAD_HDR; |
374 | copy_offset = IB_MGMT_MAD_HDR; | 457 | copy_offset = IB_MGMT_MAD_HDR; |
375 | has_rmpp_header = 0; | ||
376 | } | ||
377 | |||
378 | if (has_rmpp_header) | ||
379 | rmpp_active = ib_get_rmpp_flags(&rmpp_mad->rmpp_hdr) & | ||
380 | IB_MGMT_RMPP_FLAG_ACTIVE; | ||
381 | else | ||
382 | rmpp_active = 0; | 458 | rmpp_active = 0; |
383 | |||
384 | /* Validate that the management class can support RMPP */ | ||
385 | if (rmpp_active && !agent->rmpp_version) { | ||
386 | ret = -EINVAL; | ||
387 | goto err_ah; | ||
388 | } | 459 | } |
389 | 460 | ||
461 | data_len = count - sizeof (struct ib_user_mad) - hdr_len; | ||
390 | packet->msg = ib_create_send_mad(agent, | 462 | packet->msg = ib_create_send_mad(agent, |
391 | be32_to_cpu(packet->mad.hdr.qpn), | 463 | be32_to_cpu(packet->mad.hdr.qpn), |
392 | 0, rmpp_active, | 464 | 0, rmpp_active, hdr_len, |
393 | hdr_len, length - hdr_len, | 465 | data_len, GFP_KERNEL); |
394 | GFP_KERNEL); | ||
395 | if (IS_ERR(packet->msg)) { | 466 | if (IS_ERR(packet->msg)) { |
396 | ret = PTR_ERR(packet->msg); | 467 | ret = PTR_ERR(packet->msg); |
397 | goto err_ah; | 468 | goto err_ah; |
@@ -402,14 +473,21 @@ static ssize_t ib_umad_write(struct file *filp, const char __user *buf, | |||
402 | packet->msg->retries = packet->mad.hdr.retries; | 473 | packet->msg->retries = packet->mad.hdr.retries; |
403 | packet->msg->context[0] = packet; | 474 | packet->msg->context[0] = packet; |
404 | 475 | ||
405 | /* Copy MAD headers (RMPP header in place) */ | 476 | /* Copy MAD header. Any RMPP header is already in place. */ |
406 | memcpy(packet->msg->mad, packet->mad.data, IB_MGMT_MAD_HDR); | 477 | memcpy(packet->msg->mad, packet->mad.data, IB_MGMT_MAD_HDR); |
407 | /* Now, copy rest of message from user into send buffer */ | 478 | buf += sizeof (struct ib_user_mad); |
408 | if (copy_from_user(packet->msg->mad + copy_offset, | 479 | |
409 | buf + sizeof (struct ib_user_mad) + copy_offset, | 480 | if (!rmpp_active) { |
410 | length - copy_offset)) { | 481 | if (copy_from_user(packet->msg->mad + copy_offset, |
411 | ret = -EFAULT; | 482 | buf + copy_offset, |
412 | goto err_msg; | 483 | hdr_len + data_len - copy_offset)) { |
484 | ret = -EFAULT; | ||
485 | goto err_msg; | ||
486 | } | ||
487 | } else { | ||
488 | ret = copy_rmpp_mad(packet->msg, buf); | ||
489 | if (ret) | ||
490 | goto err_msg; | ||
413 | } | 491 | } |
414 | 492 | ||
415 | /* | 493 | /* |
@@ -433,18 +511,14 @@ static ssize_t ib_umad_write(struct file *filp, const char __user *buf, | |||
433 | goto err_msg; | 511 | goto err_msg; |
434 | 512 | ||
435 | up_read(&file->port->mutex); | 513 | up_read(&file->port->mutex); |
436 | |||
437 | return count; | 514 | return count; |
438 | 515 | ||
439 | err_msg: | 516 | err_msg: |
440 | ib_free_send_mad(packet->msg); | 517 | ib_free_send_mad(packet->msg); |
441 | |||
442 | err_ah: | 518 | err_ah: |
443 | ib_destroy_ah(ah); | 519 | ib_destroy_ah(ah); |
444 | |||
445 | err_up: | 520 | err_up: |
446 | up_read(&file->port->mutex); | 521 | up_read(&file->port->mutex); |
447 | |||
448 | err: | 522 | err: |
449 | kfree(packet); | 523 | kfree(packet); |
450 | return ret; | 524 | return ret; |
@@ -627,8 +701,11 @@ static int ib_umad_close(struct inode *inode, struct file *filp) | |||
627 | already_dead = file->agents_dead; | 701 | already_dead = file->agents_dead; |
628 | file->agents_dead = 1; | 702 | file->agents_dead = 1; |
629 | 703 | ||
630 | list_for_each_entry_safe(packet, tmp, &file->recv_list, list) | 704 | list_for_each_entry_safe(packet, tmp, &file->recv_list, list) { |
705 | if (packet->recv_wc) | ||
706 | ib_free_recv_mad(packet->recv_wc); | ||
631 | kfree(packet); | 707 | kfree(packet); |
708 | } | ||
632 | 709 | ||
633 | list_del(&file->port_list); | 710 | list_del(&file->port_list); |
634 | 711 | ||