@@ -26,13 +26,13 @@ static void assemble_qbuf_mtt_for_cmd(struct erdma_mem *mem, u32 *cfg,
26
26
27
27
if (mem -> mtt_nents > ERDMA_MAX_INLINE_MTT_ENTRIES ) {
28
28
* addr0 = mtt -> buf_dma ;
29
- * cfg |= FIELD_PREP (ERDMA_CMD_CREATE_QP_MTT_TYPE_MASK ,
30
- ERDMA_MR_INDIRECT_MTT );
29
+ * cfg |= FIELD_PREP (ERDMA_CMD_CREATE_QP_MTT_LEVEL_MASK ,
30
+ ERDMA_MR_MTT_1LEVEL );
31
31
} else {
32
32
* addr0 = mtt -> buf [0 ];
33
33
memcpy (addr1 , mtt -> buf + 1 , MTT_SIZE (mem -> mtt_nents - 1 ));
34
- * cfg |= FIELD_PREP (ERDMA_CMD_CREATE_QP_MTT_TYPE_MASK ,
35
- ERDMA_MR_INLINE_MTT );
34
+ * cfg |= FIELD_PREP (ERDMA_CMD_CREATE_QP_MTT_LEVEL_MASK ,
35
+ ERDMA_MR_MTT_0LEVEL );
36
36
}
37
37
}
38
38
@@ -70,8 +70,8 @@ static int create_qp_cmd(struct erdma_ucontext *uctx, struct erdma_qp *qp)
70
70
req .sq_mtt_cfg =
71
71
FIELD_PREP (ERDMA_CMD_CREATE_QP_PAGE_OFFSET_MASK , 0 ) |
72
72
FIELD_PREP (ERDMA_CMD_CREATE_QP_MTT_CNT_MASK , 1 ) |
73
- FIELD_PREP (ERDMA_CMD_CREATE_QP_MTT_TYPE_MASK ,
74
- ERDMA_MR_INLINE_MTT );
73
+ FIELD_PREP (ERDMA_CMD_CREATE_QP_MTT_LEVEL_MASK ,
74
+ ERDMA_MR_MTT_0LEVEL );
75
75
req .rq_mtt_cfg = req .sq_mtt_cfg ;
76
76
77
77
req .rq_buf_addr = qp -> kern_qp .rq_buf_dma_addr ;
@@ -140,12 +140,17 @@ static int regmr_cmd(struct erdma_dev *dev, struct erdma_mr *mr)
140
140
141
141
if (mr -> type == ERDMA_MR_TYPE_FRMR ||
142
142
mr -> mem .page_cnt > ERDMA_MAX_INLINE_MTT_ENTRIES ) {
143
- req .phy_addr [0 ] = mr -> mem .mtt -> buf_dma ;
144
- mtt_level = ERDMA_MR_INDIRECT_MTT ;
143
+ if (mr -> mem .mtt -> continuous ) {
144
+ req .phy_addr [0 ] = mr -> mem .mtt -> buf_dma ;
145
+ mtt_level = ERDMA_MR_MTT_1LEVEL ;
146
+ } else {
147
+ req .phy_addr [0 ] = sg_dma_address (mr -> mem .mtt -> sglist );
148
+ mtt_level = mr -> mem .mtt -> level ;
149
+ }
145
150
} else {
146
151
memcpy (req .phy_addr , mr -> mem .mtt -> buf ,
147
152
MTT_SIZE (mr -> mem .page_cnt ));
148
- mtt_level = ERDMA_MR_INLINE_MTT ;
153
+ mtt_level = ERDMA_MR_MTT_0LEVEL ;
149
154
}
150
155
151
156
req .cfg0 = FIELD_PREP (ERDMA_CMD_MR_VALID_MASK , mr -> valid ) |
@@ -167,6 +172,14 @@ static int regmr_cmd(struct erdma_dev *dev, struct erdma_mr *mr)
167
172
req .size = mr -> mem .len ;
168
173
}
169
174
175
+ if (!mr -> mem .mtt -> continuous && mr -> mem .mtt -> level > 1 ) {
176
+ req .cfg0 |= FIELD_PREP (ERDMA_CMD_MR_VERSION_MASK , 1 );
177
+ req .cfg2 |= FIELD_PREP (ERDMA_CMD_REGMR_MTT_PAGESIZE_MASK ,
178
+ PAGE_SHIFT - ERDMA_HW_PAGE_SHIFT );
179
+ req .size_h = upper_32_bits (mr -> mem .len );
180
+ req .mtt_cnt_h = mr -> mem .page_cnt >> 20 ;
181
+ }
182
+
170
183
post_cmd :
171
184
return erdma_post_cmd_wait (& dev -> cmdq , & req , sizeof (req ), NULL , NULL );
172
185
}
@@ -194,7 +207,7 @@ static int create_cq_cmd(struct erdma_ucontext *uctx, struct erdma_cq *cq)
194
207
195
208
req .cfg1 |= FIELD_PREP (ERDMA_CMD_CREATE_CQ_MTT_CNT_MASK , 1 ) |
196
209
FIELD_PREP (ERDMA_CMD_CREATE_CQ_MTT_LEVEL_MASK ,
197
- ERDMA_MR_INLINE_MTT );
210
+ ERDMA_MR_MTT_0LEVEL );
198
211
199
212
req .first_page_offset = 0 ;
200
213
req .cq_db_info_addr =
@@ -209,13 +222,13 @@ static int create_cq_cmd(struct erdma_ucontext *uctx, struct erdma_cq *cq)
209
222
req .qbuf_addr_h = upper_32_bits (mem -> mtt -> buf [0 ]);
210
223
req .cfg1 |=
211
224
FIELD_PREP (ERDMA_CMD_CREATE_CQ_MTT_LEVEL_MASK ,
212
- ERDMA_MR_INLINE_MTT );
225
+ ERDMA_MR_MTT_0LEVEL );
213
226
} else {
214
227
req .qbuf_addr_l = lower_32_bits (mem -> mtt -> buf_dma );
215
228
req .qbuf_addr_h = upper_32_bits (mem -> mtt -> buf_dma );
216
229
req .cfg1 |=
217
230
FIELD_PREP (ERDMA_CMD_CREATE_CQ_MTT_LEVEL_MASK ,
218
- ERDMA_MR_INDIRECT_MTT );
231
+ ERDMA_MR_MTT_1LEVEL );
219
232
}
220
233
req .cfg1 |= FIELD_PREP (ERDMA_CMD_CREATE_CQ_MTT_CNT_MASK ,
221
234
mem -> mtt_nents );
@@ -543,7 +556,6 @@ static struct erdma_mtt *erdma_create_cont_mtt(struct erdma_dev *dev,
543
556
size_t size )
544
557
{
545
558
struct erdma_mtt * mtt ;
546
- int ret = - ENOMEM ;
547
559
548
560
mtt = kzalloc (sizeof (* mtt ), GFP_KERNEL );
549
561
if (!mtt )
@@ -565,6 +577,104 @@ static struct erdma_mtt *erdma_create_cont_mtt(struct erdma_dev *dev,
565
577
err_free_mtt_buf :
566
578
kfree (mtt -> buf );
567
579
580
+ err_free_mtt :
581
+ kfree (mtt );
582
+
583
+ return ERR_PTR (- ENOMEM );
584
+ }
585
+
586
+ static void erdma_destroy_mtt_buf_sg (struct erdma_dev * dev ,
587
+ struct erdma_mtt * mtt )
588
+ {
589
+ dma_unmap_sg (& dev -> pdev -> dev , mtt -> sglist , mtt -> nsg , DMA_TO_DEVICE );
590
+ vfree (mtt -> sglist );
591
+ }
592
+
593
+ static void erdma_destroy_scatter_mtt (struct erdma_dev * dev ,
594
+ struct erdma_mtt * mtt )
595
+ {
596
+ erdma_destroy_mtt_buf_sg (dev , mtt );
597
+ vfree (mtt -> buf );
598
+ kfree (mtt );
599
+ }
600
+
601
+ static void erdma_init_middle_mtt (struct erdma_mtt * mtt ,
602
+ struct erdma_mtt * low_mtt )
603
+ {
604
+ struct scatterlist * sg ;
605
+ u32 idx = 0 , i ;
606
+
607
+ for_each_sg (low_mtt -> sglist , sg , low_mtt -> nsg , i )
608
+ mtt -> buf [idx ++ ] = sg_dma_address (sg );
609
+ }
610
+
611
+ static int erdma_create_mtt_buf_sg (struct erdma_dev * dev , struct erdma_mtt * mtt )
612
+ {
613
+ struct scatterlist * sglist ;
614
+ void * buf = mtt -> buf ;
615
+ u32 npages , i , nsg ;
616
+ struct page * pg ;
617
+
618
+ /* Failed if buf is not page aligned */
619
+ if ((uintptr_t )buf & ~PAGE_MASK )
620
+ return - EINVAL ;
621
+
622
+ npages = DIV_ROUND_UP (mtt -> size , PAGE_SIZE );
623
+ sglist = vzalloc (npages * sizeof (* sglist ));
624
+ if (!sglist )
625
+ return - ENOMEM ;
626
+
627
+ sg_init_table (sglist , npages );
628
+ for (i = 0 ; i < npages ; i ++ ) {
629
+ pg = vmalloc_to_page (buf );
630
+ if (!pg )
631
+ goto err ;
632
+ sg_set_page (& sglist [i ], pg , PAGE_SIZE , 0 );
633
+ buf += PAGE_SIZE ;
634
+ }
635
+
636
+ nsg = dma_map_sg (& dev -> pdev -> dev , sglist , npages , DMA_TO_DEVICE );
637
+ if (!nsg )
638
+ goto err ;
639
+
640
+ mtt -> sglist = sglist ;
641
+ mtt -> nsg = nsg ;
642
+
643
+ return 0 ;
644
+ err :
645
+ vfree (sglist );
646
+
647
+ return - ENOMEM ;
648
+ }
649
+
650
+ static struct erdma_mtt * erdma_create_scatter_mtt (struct erdma_dev * dev ,
651
+ size_t size )
652
+ {
653
+ struct erdma_mtt * mtt ;
654
+ int ret = - ENOMEM ;
655
+
656
+ mtt = kzalloc (sizeof (* mtt ), GFP_KERNEL );
657
+ if (!mtt )
658
+ return NULL ;
659
+
660
+ mtt -> size = ALIGN (size , PAGE_SIZE );
661
+ mtt -> buf = vzalloc (mtt -> size );
662
+ mtt -> continuous = false;
663
+ if (!mtt -> buf )
664
+ goto err_free_mtt ;
665
+
666
+ ret = erdma_create_mtt_buf_sg (dev , mtt );
667
+ if (ret )
668
+ goto err_free_mtt_buf ;
669
+
670
+ ibdev_dbg (& dev -> ibdev , "create scatter mtt, size:%lu, nsg:%u\n" ,
671
+ mtt -> size , mtt -> nsg );
672
+
673
+ return mtt ;
674
+
675
+ err_free_mtt_buf :
676
+ vfree (mtt -> buf );
677
+
568
678
err_free_mtt :
569
679
kfree (mtt );
570
680
@@ -574,28 +684,77 @@ static struct erdma_mtt *erdma_create_cont_mtt(struct erdma_dev *dev,
574
684
static struct erdma_mtt * erdma_create_mtt (struct erdma_dev * dev , size_t size ,
575
685
bool force_continuous )
576
686
{
687
+ struct erdma_mtt * mtt , * tmp_mtt ;
688
+ int ret , level = 0 ;
689
+
577
690
ibdev_dbg (& dev -> ibdev , "create_mtt, size:%lu, force cont:%d\n" , size ,
578
691
force_continuous );
579
692
693
+ if (!(dev -> attrs .cap_flags & ERDMA_DEV_CAP_FLAGS_MTT_VA ))
694
+ force_continuous = true;
695
+
580
696
if (force_continuous )
581
697
return erdma_create_cont_mtt (dev , size );
582
698
583
- return ERR_PTR (- EOPNOTSUPP );
699
+ mtt = erdma_create_scatter_mtt (dev , size );
700
+ if (IS_ERR (mtt ))
701
+ return mtt ;
702
+ level = 1 ;
703
+
704
+ /* convergence the mtt table. */
705
+ while (mtt -> nsg != 1 && level <= 3 ) {
706
+ tmp_mtt = erdma_create_scatter_mtt (dev , MTT_SIZE (mtt -> nsg ));
707
+ if (IS_ERR (tmp_mtt )) {
708
+ ret = PTR_ERR (tmp_mtt );
709
+ goto err_free_mtt ;
710
+ }
711
+ erdma_init_middle_mtt (tmp_mtt , mtt );
712
+ tmp_mtt -> low_level = mtt ;
713
+ mtt = tmp_mtt ;
714
+ level ++ ;
715
+ }
716
+
717
+ if (level > 3 ) {
718
+ ret = - ENOMEM ;
719
+ goto err_free_mtt ;
720
+ }
721
+
722
+ mtt -> level = level ;
723
+ ibdev_dbg (& dev -> ibdev , "top mtt: level:%d, dma_addr 0x%llx\n" ,
724
+ mtt -> level , mtt -> sglist [0 ].dma_address );
725
+
726
+ return mtt ;
727
+ err_free_mtt :
728
+ while (mtt ) {
729
+ tmp_mtt = mtt -> low_level ;
730
+ erdma_destroy_scatter_mtt (dev , mtt );
731
+ mtt = tmp_mtt ;
732
+ }
733
+
734
+ return ERR_PTR (ret );
584
735
}
585
736
586
737
static void erdma_destroy_mtt (struct erdma_dev * dev , struct erdma_mtt * mtt )
587
738
{
739
+ struct erdma_mtt * tmp_mtt ;
740
+
588
741
if (mtt -> continuous ) {
589
742
dma_unmap_single (& dev -> pdev -> dev , mtt -> buf_dma , mtt -> size ,
590
743
DMA_TO_DEVICE );
591
744
kfree (mtt -> buf );
592
745
kfree (mtt );
746
+ } else {
747
+ while (mtt ) {
748
+ tmp_mtt = mtt -> low_level ;
749
+ erdma_destroy_scatter_mtt (dev , mtt );
750
+ mtt = tmp_mtt ;
751
+ }
593
752
}
594
753
}
595
754
596
755
static int get_mtt_entries (struct erdma_dev * dev , struct erdma_mem * mem ,
597
756
u64 start , u64 len , int access , u64 virt ,
598
- unsigned long req_page_size , u8 force_indirect_mtt )
757
+ unsigned long req_page_size , bool force_continuous )
599
758
{
600
759
int ret = 0 ;
601
760
@@ -612,7 +771,8 @@ static int get_mtt_entries(struct erdma_dev *dev, struct erdma_mem *mem,
612
771
mem -> page_offset = start & (mem -> page_size - 1 );
613
772
mem -> mtt_nents = ib_umem_num_dma_blocks (mem -> umem , mem -> page_size );
614
773
mem -> page_cnt = mem -> mtt_nents ;
615
- mem -> mtt = erdma_create_mtt (dev , MTT_SIZE (mem -> page_cnt ), true);
774
+ mem -> mtt = erdma_create_mtt (dev , MTT_SIZE (mem -> page_cnt ),
775
+ force_continuous );
616
776
if (IS_ERR (mem -> mtt )) {
617
777
ret = PTR_ERR (mem -> mtt );
618
778
goto error_ret ;
@@ -717,7 +877,7 @@ static int init_user_qp(struct erdma_qp *qp, struct erdma_ucontext *uctx,
717
877
718
878
ret = get_mtt_entries (qp -> dev , & qp -> user_qp .sq_mem , va ,
719
879
qp -> attrs .sq_size << SQEBB_SHIFT , 0 , va ,
720
- (SZ_1M - SZ_4K ), 1 );
880
+ (SZ_1M - SZ_4K ), true );
721
881
if (ret )
722
882
return ret ;
723
883
@@ -726,7 +886,7 @@ static int init_user_qp(struct erdma_qp *qp, struct erdma_ucontext *uctx,
726
886
727
887
ret = get_mtt_entries (qp -> dev , & qp -> user_qp .rq_mem , va + rq_offset ,
728
888
qp -> attrs .rq_size << RQE_SHIFT , 0 , va + rq_offset ,
729
- (SZ_1M - SZ_4K ), 1 );
889
+ (SZ_1M - SZ_4K ), true );
730
890
if (ret )
731
891
goto put_sq_mtt ;
732
892
@@ -998,7 +1158,7 @@ struct ib_mr *erdma_reg_user_mr(struct ib_pd *ibpd, u64 start, u64 len,
998
1158
return ERR_PTR (- ENOMEM );
999
1159
1000
1160
ret = get_mtt_entries (dev , & mr -> mem , start , len , access , virt ,
1001
- SZ_2G - SZ_4K , 0 );
1161
+ SZ_2G - SZ_4K , false );
1002
1162
if (ret )
1003
1163
goto err_out_free ;
1004
1164
@@ -1423,7 +1583,7 @@ static int erdma_init_user_cq(struct erdma_ucontext *ctx, struct erdma_cq *cq,
1423
1583
1424
1584
ret = get_mtt_entries (dev , & cq -> user_cq .qbuf_mem , ureq -> qbuf_va ,
1425
1585
ureq -> qbuf_len , 0 , ureq -> qbuf_va , SZ_64M - SZ_4K ,
1426
- 1 );
1586
+ true );
1427
1587
if (ret )
1428
1588
return ret ;
1429
1589
0 commit comments