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