18c2ecf20Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright(c) 2016 Intel Corporation. 48c2ecf20Sopenharmony_ci */ 58c2ecf20Sopenharmony_ci 68c2ecf20Sopenharmony_ci#ifndef DEF_RDMAVT_INCMR_H 78c2ecf20Sopenharmony_ci#define DEF_RDMAVT_INCMR_H 88c2ecf20Sopenharmony_ci 98c2ecf20Sopenharmony_ci/* 108c2ecf20Sopenharmony_ci * For Memory Regions. This stuff should probably be moved into rdmavt/mr.h once 118c2ecf20Sopenharmony_ci * drivers no longer need access to the MR directly. 128c2ecf20Sopenharmony_ci */ 138c2ecf20Sopenharmony_ci#include <linux/percpu-refcount.h> 148c2ecf20Sopenharmony_ci 158c2ecf20Sopenharmony_ci/* 168c2ecf20Sopenharmony_ci * A segment is a linear region of low physical memory. 178c2ecf20Sopenharmony_ci * Used by the verbs layer. 188c2ecf20Sopenharmony_ci */ 198c2ecf20Sopenharmony_cistruct rvt_seg { 208c2ecf20Sopenharmony_ci void *vaddr; 218c2ecf20Sopenharmony_ci size_t length; 228c2ecf20Sopenharmony_ci}; 238c2ecf20Sopenharmony_ci 248c2ecf20Sopenharmony_ci/* The number of rvt_segs that fit in a page. */ 258c2ecf20Sopenharmony_ci#define RVT_SEGSZ (PAGE_SIZE / sizeof(struct rvt_seg)) 268c2ecf20Sopenharmony_ci 278c2ecf20Sopenharmony_cistruct rvt_segarray { 288c2ecf20Sopenharmony_ci struct rvt_seg segs[RVT_SEGSZ]; 298c2ecf20Sopenharmony_ci}; 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_cistruct rvt_mregion { 328c2ecf20Sopenharmony_ci struct ib_pd *pd; /* shares refcnt of ibmr.pd */ 338c2ecf20Sopenharmony_ci u64 user_base; /* User's address for this region */ 348c2ecf20Sopenharmony_ci u64 iova; /* IB start address of this region */ 358c2ecf20Sopenharmony_ci size_t length; 368c2ecf20Sopenharmony_ci u32 lkey; 378c2ecf20Sopenharmony_ci u32 offset; /* offset (bytes) to start of region */ 388c2ecf20Sopenharmony_ci int access_flags; 398c2ecf20Sopenharmony_ci u32 max_segs; /* number of rvt_segs in all the arrays */ 408c2ecf20Sopenharmony_ci u32 mapsz; /* size of the map array */ 418c2ecf20Sopenharmony_ci atomic_t lkey_invalid; /* true if current lkey is invalid */ 428c2ecf20Sopenharmony_ci u8 page_shift; /* 0 - non unform/non powerof2 sizes */ 438c2ecf20Sopenharmony_ci u8 lkey_published; /* in global table */ 448c2ecf20Sopenharmony_ci struct percpu_ref refcount; 458c2ecf20Sopenharmony_ci struct completion comp; /* complete when refcount goes to zero */ 468c2ecf20Sopenharmony_ci struct rvt_segarray *map[]; /* the segments */ 478c2ecf20Sopenharmony_ci}; 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_ci#define RVT_MAX_LKEY_TABLE_BITS 23 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_cistruct rvt_lkey_table { 528c2ecf20Sopenharmony_ci /* read mostly fields */ 538c2ecf20Sopenharmony_ci u32 max; /* size of the table */ 548c2ecf20Sopenharmony_ci u32 shift; /* lkey/rkey shift */ 558c2ecf20Sopenharmony_ci struct rvt_mregion __rcu **table; 568c2ecf20Sopenharmony_ci /* writeable fields */ 578c2ecf20Sopenharmony_ci /* protect changes in this struct */ 588c2ecf20Sopenharmony_ci spinlock_t lock ____cacheline_aligned_in_smp; 598c2ecf20Sopenharmony_ci u32 next; /* next unused index (speeds search) */ 608c2ecf20Sopenharmony_ci u32 gen; /* generation count */ 618c2ecf20Sopenharmony_ci}; 628c2ecf20Sopenharmony_ci 638c2ecf20Sopenharmony_ci/* 648c2ecf20Sopenharmony_ci * These keep track of the copy progress within a memory region. 658c2ecf20Sopenharmony_ci * Used by the verbs layer. 668c2ecf20Sopenharmony_ci */ 678c2ecf20Sopenharmony_cistruct rvt_sge { 688c2ecf20Sopenharmony_ci struct rvt_mregion *mr; 698c2ecf20Sopenharmony_ci void *vaddr; /* kernel virtual address of segment */ 708c2ecf20Sopenharmony_ci u32 sge_length; /* length of the SGE */ 718c2ecf20Sopenharmony_ci u32 length; /* remaining length of the segment */ 728c2ecf20Sopenharmony_ci u16 m; /* current index: mr->map[m] */ 738c2ecf20Sopenharmony_ci u16 n; /* current index: mr->map[m]->segs[n] */ 748c2ecf20Sopenharmony_ci}; 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_cistruct rvt_sge_state { 778c2ecf20Sopenharmony_ci struct rvt_sge *sg_list; /* next SGE to be used if any */ 788c2ecf20Sopenharmony_ci struct rvt_sge sge; /* progress state for the current SGE */ 798c2ecf20Sopenharmony_ci u32 total_len; 808c2ecf20Sopenharmony_ci u8 num_sge; 818c2ecf20Sopenharmony_ci}; 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_cistatic inline void rvt_put_mr(struct rvt_mregion *mr) 848c2ecf20Sopenharmony_ci{ 858c2ecf20Sopenharmony_ci percpu_ref_put(&mr->refcount); 868c2ecf20Sopenharmony_ci} 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_cistatic inline void rvt_get_mr(struct rvt_mregion *mr) 898c2ecf20Sopenharmony_ci{ 908c2ecf20Sopenharmony_ci percpu_ref_get(&mr->refcount); 918c2ecf20Sopenharmony_ci} 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_cistatic inline void rvt_put_ss(struct rvt_sge_state *ss) 948c2ecf20Sopenharmony_ci{ 958c2ecf20Sopenharmony_ci while (ss->num_sge) { 968c2ecf20Sopenharmony_ci rvt_put_mr(ss->sge.mr); 978c2ecf20Sopenharmony_ci if (--ss->num_sge) 988c2ecf20Sopenharmony_ci ss->sge = *ss->sg_list++; 998c2ecf20Sopenharmony_ci } 1008c2ecf20Sopenharmony_ci} 1018c2ecf20Sopenharmony_ci 1028c2ecf20Sopenharmony_cistatic inline u32 rvt_get_sge_length(struct rvt_sge *sge, u32 length) 1038c2ecf20Sopenharmony_ci{ 1048c2ecf20Sopenharmony_ci u32 len = sge->length; 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_ci if (len > length) 1078c2ecf20Sopenharmony_ci len = length; 1088c2ecf20Sopenharmony_ci if (len > sge->sge_length) 1098c2ecf20Sopenharmony_ci len = sge->sge_length; 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_ci return len; 1128c2ecf20Sopenharmony_ci} 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_cistatic inline void rvt_update_sge(struct rvt_sge_state *ss, u32 length, 1158c2ecf20Sopenharmony_ci bool release) 1168c2ecf20Sopenharmony_ci{ 1178c2ecf20Sopenharmony_ci struct rvt_sge *sge = &ss->sge; 1188c2ecf20Sopenharmony_ci 1198c2ecf20Sopenharmony_ci sge->vaddr += length; 1208c2ecf20Sopenharmony_ci sge->length -= length; 1218c2ecf20Sopenharmony_ci sge->sge_length -= length; 1228c2ecf20Sopenharmony_ci if (sge->sge_length == 0) { 1238c2ecf20Sopenharmony_ci if (release) 1248c2ecf20Sopenharmony_ci rvt_put_mr(sge->mr); 1258c2ecf20Sopenharmony_ci if (--ss->num_sge) 1268c2ecf20Sopenharmony_ci *sge = *ss->sg_list++; 1278c2ecf20Sopenharmony_ci } else if (sge->length == 0 && sge->mr->lkey) { 1288c2ecf20Sopenharmony_ci if (++sge->n >= RVT_SEGSZ) { 1298c2ecf20Sopenharmony_ci if (++sge->m >= sge->mr->mapsz) 1308c2ecf20Sopenharmony_ci return; 1318c2ecf20Sopenharmony_ci sge->n = 0; 1328c2ecf20Sopenharmony_ci } 1338c2ecf20Sopenharmony_ci sge->vaddr = sge->mr->map[sge->m]->segs[sge->n].vaddr; 1348c2ecf20Sopenharmony_ci sge->length = sge->mr->map[sge->m]->segs[sge->n].length; 1358c2ecf20Sopenharmony_ci } 1368c2ecf20Sopenharmony_ci} 1378c2ecf20Sopenharmony_ci 1388c2ecf20Sopenharmony_cistatic inline void rvt_skip_sge(struct rvt_sge_state *ss, u32 length, 1398c2ecf20Sopenharmony_ci bool release) 1408c2ecf20Sopenharmony_ci{ 1418c2ecf20Sopenharmony_ci struct rvt_sge *sge = &ss->sge; 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_ci while (length) { 1448c2ecf20Sopenharmony_ci u32 len = rvt_get_sge_length(sge, length); 1458c2ecf20Sopenharmony_ci 1468c2ecf20Sopenharmony_ci WARN_ON_ONCE(len == 0); 1478c2ecf20Sopenharmony_ci rvt_update_sge(ss, len, release); 1488c2ecf20Sopenharmony_ci length -= len; 1498c2ecf20Sopenharmony_ci } 1508c2ecf20Sopenharmony_ci} 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_cibool rvt_ss_has_lkey(struct rvt_sge_state *ss, u32 lkey); 1538c2ecf20Sopenharmony_cibool rvt_mr_has_lkey(struct rvt_mregion *mr, u32 lkey); 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_ci#endif /* DEF_RDMAVT_INCMRH */ 156