Skip to content

Commit 4a35339

Browse files
shirazsaleemjgunthorpe
authored andcommitted
RDMA/umem: Add API to find best driver supported page size in an MR
This helper iterates through the SG list to find the best page size to use from a bitmap of HW supported page sizes. Drivers that support multiple page sizes, but not mixed sizes in an MR can use this API. Suggested-by: Jason Gunthorpe <[email protected]> Signed-off-by: Shiraz Saleem <[email protected]> Signed-off-by: Jason Gunthorpe <[email protected]>
1 parent 4c4b199 commit 4a35339

File tree

3 files changed

+84
-0
lines changed

3 files changed

+84
-0
lines changed

drivers/infiniband/core/umem.c

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,57 @@ static struct scatterlist *ib_umem_add_sg_table(struct scatterlist *sg,
130130
return sg;
131131
}
132132

133+
/**
134+
* ib_umem_find_best_pgsz - Find best HW page size to use for this MR
135+
*
136+
* @umem: umem struct
137+
* @pgsz_bitmap: bitmap of HW supported page sizes
138+
* @virt: IOVA
139+
*
140+
* This helper is intended for HW that support multiple page
141+
* sizes but can do only a single page size in an MR.
142+
*
143+
* Returns 0 if the umem requires page sizes not supported by
144+
* the driver to be mapped. Drivers always supporting PAGE_SIZE
145+
* or smaller will never see a 0 result.
146+
*/
147+
unsigned long ib_umem_find_best_pgsz(struct ib_umem *umem,
148+
unsigned long pgsz_bitmap,
149+
unsigned long virt)
150+
{
151+
struct scatterlist *sg;
152+
unsigned int best_pg_bit;
153+
unsigned long va, pgoff;
154+
dma_addr_t mask;
155+
int i;
156+
157+
/* At minimum, drivers must support PAGE_SIZE or smaller */
158+
if (WARN_ON(!(pgsz_bitmap & GENMASK(PAGE_SHIFT, 0))))
159+
return 0;
160+
161+
va = virt;
162+
/* max page size not to exceed MR length */
163+
mask = roundup_pow_of_two(umem->length);
164+
/* offset into first SGL */
165+
pgoff = umem->address & ~PAGE_MASK;
166+
167+
for_each_sg(umem->sg_head.sgl, sg, umem->nmap, i) {
168+
/* Walk SGL and reduce max page size if VA/PA bits differ
169+
* for any address.
170+
*/
171+
mask |= (sg_dma_address(sg) + pgoff) ^ va;
172+
if (i && i != (umem->nmap - 1))
173+
/* restrict by length as well for interior SGEs */
174+
mask |= sg_dma_len(sg);
175+
va += sg_dma_len(sg) - pgoff;
176+
pgoff = 0;
177+
}
178+
best_pg_bit = rdma_find_pg_bit(mask, pgsz_bitmap);
179+
180+
return BIT_ULL(best_pg_bit);
181+
}
182+
EXPORT_SYMBOL(ib_umem_find_best_pgsz);
183+
133184
/**
134185
* ib_umem_get - Pin and DMA map userspace memory.
135186
*

include/rdma/ib_umem.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,9 @@ void ib_umem_release(struct ib_umem *umem);
8787
int ib_umem_page_count(struct ib_umem *umem);
8888
int ib_umem_copy_from(void *dst, struct ib_umem *umem, size_t offset,
8989
size_t length);
90+
unsigned long ib_umem_find_best_pgsz(struct ib_umem *umem,
91+
unsigned long pgsz_bitmap,
92+
unsigned long virt);
9093

9194
#else /* CONFIG_INFINIBAND_USER_MEM */
9295

@@ -104,6 +107,12 @@ static inline int ib_umem_copy_from(void *dst, struct ib_umem *umem, size_t offs
104107
size_t length) {
105108
return -EINVAL;
106109
}
110+
static inline int ib_umem_find_best_pgsz(struct ib_umem *umem,
111+
unsigned long pgsz_bitmap,
112+
unsigned long virt) {
113+
return -EINVAL;
114+
}
115+
107116
#endif /* CONFIG_INFINIBAND_USER_MEM */
108117

109118
#endif /* IB_UMEM_H */

include/rdma/ib_verbs.h

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3250,6 +3250,30 @@ static inline bool rdma_cap_read_inv(struct ib_device *dev, u32 port_num)
32503250
return rdma_protocol_iwarp(dev, port_num);
32513251
}
32523252

3253+
/**
3254+
* rdma_find_pg_bit - Find page bit given address and HW supported page sizes
3255+
*
3256+
* @addr: address
3257+
* @pgsz_bitmap: bitmap of HW supported page sizes
3258+
*/
3259+
static inline unsigned int rdma_find_pg_bit(unsigned long addr,
3260+
unsigned long pgsz_bitmap)
3261+
{
3262+
unsigned long align;
3263+
unsigned long pgsz;
3264+
3265+
align = addr & -addr;
3266+
3267+
/* Find page bit such that addr is aligned to the highest supported
3268+
* HW page size
3269+
*/
3270+
pgsz = pgsz_bitmap & ~(-align << 1);
3271+
if (!pgsz)
3272+
return __ffs(pgsz_bitmap);
3273+
3274+
return __fls(pgsz);
3275+
}
3276+
32533277
int ib_set_vf_link_state(struct ib_device *device, int vf, u8 port,
32543278
int state);
32553279
int ib_get_vf_config(struct ib_device *device, int vf, u8 port,

0 commit comments

Comments
 (0)