From: Chuck Lever <chuck.lever@xxxxxxxxxx> These are roughly equivalent to the fields used for managing scatterlist DMA mapping. Cc: Jens Axboe <axboe@xxxxxxxxx> Cc: Christoph Hellwig <hch@xxxxxx> Cc: David Howells <dhowells@xxxxxxxxxx> Cc: iommu@xxxxxxxxxxxxxxx Cc: linux-rdma@xxxxxxxxxxxxxxx Signed-off-by: Chuck Lever <chuck.lever@xxxxxxxxxx> --- include/linux/bvec.h | 143 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 143 insertions(+) diff --git a/include/linux/bvec.h b/include/linux/bvec.h index 555aae5448ae..1074f34a4e8f 100644 --- a/include/linux/bvec.h +++ b/include/linux/bvec.h @@ -13,6 +13,7 @@ #include <linux/limits.h> #include <linux/minmax.h> #include <linux/types.h> +#include <asm/io.h> struct page; @@ -32,6 +33,13 @@ struct bio_vec { struct page *bv_page; unsigned int bv_len; unsigned int bv_offset; + dma_addr_t bv_dma_address; +#ifdef CONFIG_NEED_SG_DMA_LENGTH + unsigned int bv_dma_length; +#endif +#ifdef CONFIG_NEED_SG_DMA_FLAGS + unsigned int bv_dma_flags; +#endif }; /** @@ -74,6 +82,24 @@ static inline void bvec_set_virt(struct bio_vec *bv, void *vaddr, bvec_set_page(bv, virt_to_page(vaddr), len, offset_in_page(vaddr)); } +/** + * bv_phys - return physical address of a bio_vec + * @bv: bio_vec + */ +static inline dma_addr_t bv_phys(struct bio_vec *bv) +{ + return page_to_phys(bv->bv_page) + bv->bv_offset; +} + +/** + * bv_virt - return virtual address of a bio_vec + * @bv: bio_vec + */ +static inline void *bv_virt(struct bio_vec *bv) +{ + return page_address(bv->bv_page) + bv->bv_offset; +} + struct bvec_iter { sector_t bi_sector; /* device address in 512 byte sectors */ @@ -280,4 +306,121 @@ static inline void *bvec_virt(struct bio_vec *bvec) return page_address(bvec->bv_page) + bvec->bv_offset; } +/* + * These macros should be used after a dma_map_bvecs call has been done + * to get bus addresses of each of the bio_vec array entries and their + * lengths. You should work only with the number of bio_vec array entries + * dma_map_bvecs returns, or alternatively stop on the first bv_dma_len(bv) + * which is 0. + */ +#define bv_dma_address(bv) ((bv)->bv_dma_address) + +#ifdef CONFIG_NEED_SG_DMA_LENGTH +#define bv_dma_len(bv) ((bv)->bv_dma_length) +#else +#define bv_dma_len(bv) ((bv)->bv_len) +#endif + +/* + * On 64-bit architectures there is a 4-byte padding in struct scatterlist + * (assuming also CONFIG_NEED_SG_DMA_LENGTH is set). Use this padding for DMA + * flags bits to indicate when a specific dma address is a bus address or the + * buffer may have been bounced via SWIOTLB. + */ +#ifdef CONFIG_NEED_SG_DMA_FLAGS + +#define BV_DMA_BUS_ADDRESS BIT(0) +#define BV_DMA_SWIOTLB BIT(1) + +/** + * bv_dma_is_bus_address - Return whether a given segment was marked + * as a bus address + * @bv: bio_vec array entry + * + * Description: + * Returns true if bv_dma_mark_bus_address() has been called on + * this bio_vec. + **/ +static inline bool bv_dma_is_bus_address(struct bio_vec *bv) +{ + return bv->bv_dma_flags & BV_DMA_BUS_ADDRESS; +} + +/** + * bv_dma_mark_bus_address - Mark the bio_vec entry as a bus address + * @bv: bio_vec array entry + * + * Description: + * Marks the passed-in bv entry to indicate that the dma_address is + * a bus address and doesn't need to be unmapped. This should only be + * used by dma_map_bvecs() implementations to mark bus addresses + * so they can be properly cleaned up in dma_unmap_bvecs(). + **/ +static inline void bv_dma_mark_bus_address(struct bio_vec *bv) +{ + bv->bv_dma_flags |= BV_DMA_BUS_ADDRESS; +} + +/** + * bv_unmark_bus_address - Unmark the bio_vec entry as a bus address + * @bv: bio_vec array entry + * + * Description: + * Clears the bus address mark. + **/ +static inline void bv_dma_unmark_bus_address(struct bio_vec *bv) +{ + bv->bv_dma_flags &= ~BV_DMA_BUS_ADDRESS; +} + +/** + * bv_dma_is_swiotlb - Return whether the bio_vec was marked for SWIOTLB + * bouncing + * @bv: bio_vec array entry + * + * Description: + * Returns true if the bio_vec was marked for SWIOTLB bouncing. Not all + * elements may have been bounced, so the caller would have to check + * individual BV entries with is_swiotlb_buffer(). + */ +static inline bool bv_dma_is_swiotlb(struct bio_vec *bv) +{ + return bv->bv_dma_flags & BV_DMA_SWIOTLB; +} + +/** + * bv_dma_mark_swiotlb - Mark the bio_vec for SWIOTLB bouncing + * @bv: bio_vec array entry + * + * Description: + * Marks a a bio_vec for SWIOTLB bounce. Not all bio_vec entries may + * be bounced. + */ +static inline void bv_dma_mark_swiotlb(struct bio_vec *bv) +{ + bv->bv_dma_flags |= BV_DMA_SWIOTLB; +} + +#else + +static inline bool bv_dma_is_bus_address(struct bio_vec *bv) +{ + return false; +} +static inline void bv_dma_mark_bus_address(struct bio_vec *bv) +{ +} +static inline void bv_dma_unmark_bus_address(struct bio_vec *bv) +{ +} +static inline bool bv_dma_is_swiotlb(struct bio_vec *bv) +{ + return false; +} +static inline void bv_dma_mark_swiotlb(struct bio_vec *bv) +{ +} + +#endif /* CONFIG_NEED_SG_DMA_FLAGS */ + #endif /* __LINUX_BVEC_H */