mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 10:40:15 +02:00 
			
		
		
		
	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 <jgg@ziepe.ca> Signed-off-by: Shiraz Saleem <shiraz.saleem@intel.com> Signed-off-by: Jason Gunthorpe <jgg@mellanox.com>
This commit is contained in:
		
							parent
							
								
									4c4b1996b5
								
							
						
					
					
						commit
						4a35339958
					
				
					 3 changed files with 84 additions and 0 deletions
				
			
		| 
						 | 
					@ -130,6 +130,57 @@ static struct scatterlist *ib_umem_add_sg_table(struct scatterlist *sg,
 | 
				
			||||||
	return sg;
 | 
						return sg;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * ib_umem_find_best_pgsz - Find best HW page size to use for this MR
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * @umem: umem struct
 | 
				
			||||||
 | 
					 * @pgsz_bitmap: bitmap of HW supported page sizes
 | 
				
			||||||
 | 
					 * @virt: IOVA
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * This helper is intended for HW that support multiple page
 | 
				
			||||||
 | 
					 * sizes but can do only a single page size in an MR.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Returns 0 if the umem requires page sizes not supported by
 | 
				
			||||||
 | 
					 * the driver to be mapped. Drivers always supporting PAGE_SIZE
 | 
				
			||||||
 | 
					 * or smaller will never see a 0 result.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					unsigned long ib_umem_find_best_pgsz(struct ib_umem *umem,
 | 
				
			||||||
 | 
									     unsigned long pgsz_bitmap,
 | 
				
			||||||
 | 
									     unsigned long virt)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct scatterlist *sg;
 | 
				
			||||||
 | 
						unsigned int best_pg_bit;
 | 
				
			||||||
 | 
						unsigned long va, pgoff;
 | 
				
			||||||
 | 
						dma_addr_t mask;
 | 
				
			||||||
 | 
						int i;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* At minimum, drivers must support PAGE_SIZE or smaller */
 | 
				
			||||||
 | 
						if (WARN_ON(!(pgsz_bitmap & GENMASK(PAGE_SHIFT, 0))))
 | 
				
			||||||
 | 
							return 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						va = virt;
 | 
				
			||||||
 | 
						/* max page size not to exceed MR length */
 | 
				
			||||||
 | 
						mask = roundup_pow_of_two(umem->length);
 | 
				
			||||||
 | 
						/* offset into first SGL */
 | 
				
			||||||
 | 
						pgoff = umem->address & ~PAGE_MASK;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for_each_sg(umem->sg_head.sgl, sg, umem->nmap, i) {
 | 
				
			||||||
 | 
							/* Walk SGL and reduce max page size if VA/PA bits differ
 | 
				
			||||||
 | 
							 * for any address.
 | 
				
			||||||
 | 
							 */
 | 
				
			||||||
 | 
							mask |= (sg_dma_address(sg) + pgoff) ^ va;
 | 
				
			||||||
 | 
							if (i && i != (umem->nmap - 1))
 | 
				
			||||||
 | 
								/* restrict by length as well for interior SGEs */
 | 
				
			||||||
 | 
								mask |= sg_dma_len(sg);
 | 
				
			||||||
 | 
							va += sg_dma_len(sg) - pgoff;
 | 
				
			||||||
 | 
							pgoff = 0;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						best_pg_bit = rdma_find_pg_bit(mask, pgsz_bitmap);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return BIT_ULL(best_pg_bit);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					EXPORT_SYMBOL(ib_umem_find_best_pgsz);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * ib_umem_get - Pin and DMA map userspace memory.
 | 
					 * ib_umem_get - Pin and DMA map userspace memory.
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -87,6 +87,9 @@ void ib_umem_release(struct ib_umem *umem);
 | 
				
			||||||
int ib_umem_page_count(struct ib_umem *umem);
 | 
					int ib_umem_page_count(struct ib_umem *umem);
 | 
				
			||||||
int ib_umem_copy_from(void *dst, struct ib_umem *umem, size_t offset,
 | 
					int ib_umem_copy_from(void *dst, struct ib_umem *umem, size_t offset,
 | 
				
			||||||
		      size_t length);
 | 
							      size_t length);
 | 
				
			||||||
 | 
					unsigned long ib_umem_find_best_pgsz(struct ib_umem *umem,
 | 
				
			||||||
 | 
									     unsigned long pgsz_bitmap,
 | 
				
			||||||
 | 
									     unsigned long virt);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#else /* CONFIG_INFINIBAND_USER_MEM */
 | 
					#else /* CONFIG_INFINIBAND_USER_MEM */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -104,6 +107,12 @@ static inline int ib_umem_copy_from(void *dst, struct ib_umem *umem, size_t offs
 | 
				
			||||||
		      		    size_t length) {
 | 
							      		    size_t length) {
 | 
				
			||||||
	return -EINVAL;
 | 
						return -EINVAL;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					static inline int ib_umem_find_best_pgsz(struct ib_umem *umem,
 | 
				
			||||||
 | 
										 unsigned long pgsz_bitmap,
 | 
				
			||||||
 | 
										 unsigned long virt) {
 | 
				
			||||||
 | 
						return -EINVAL;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#endif /* CONFIG_INFINIBAND_USER_MEM */
 | 
					#endif /* CONFIG_INFINIBAND_USER_MEM */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#endif /* IB_UMEM_H */
 | 
					#endif /* IB_UMEM_H */
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -3250,6 +3250,30 @@ static inline bool rdma_cap_read_inv(struct ib_device *dev, u32 port_num)
 | 
				
			||||||
	return rdma_protocol_iwarp(dev, port_num);
 | 
						return rdma_protocol_iwarp(dev, port_num);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * rdma_find_pg_bit - Find page bit given address and HW supported page sizes
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * @addr: address
 | 
				
			||||||
 | 
					 * @pgsz_bitmap: bitmap of HW supported page sizes
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					static inline unsigned int rdma_find_pg_bit(unsigned long addr,
 | 
				
			||||||
 | 
										    unsigned long pgsz_bitmap)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						unsigned long align;
 | 
				
			||||||
 | 
						unsigned long pgsz;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						align = addr & -addr;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Find page bit such that addr is aligned to the highest supported
 | 
				
			||||||
 | 
						 * HW page size
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						pgsz = pgsz_bitmap & ~(-align << 1);
 | 
				
			||||||
 | 
						if (!pgsz)
 | 
				
			||||||
 | 
							return __ffs(pgsz_bitmap);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return __fls(pgsz);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int ib_set_vf_link_state(struct ib_device *device, int vf, u8 port,
 | 
					int ib_set_vf_link_state(struct ib_device *device, int vf, u8 port,
 | 
				
			||||||
			 int state);
 | 
								 int state);
 | 
				
			||||||
int ib_get_vf_config(struct ib_device *device, int vf, u8 port,
 | 
					int ib_get_vf_config(struct ib_device *device, int vf, u8 port,
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue