[PATCH rdma-next 01/43] RDMA/cm: Add naive SET/GET implementations to hide CM wire format

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



From: Leon Romanovsky <leonro@xxxxxxxxxxxx>

There is no separation between RDMA-CM wire format as it is declared in
IBTA and kernel logic which implements needed support. Such situation
causes to many mistakes in conversion between big-endian (wire format)
and CPU format used by kernel. It also mixes RDMA core code with
combination of uXX and beXX variables.

The idea that every converted variable will have two fields which
describes the byte offset and mask for the access, e.g.

 #define CM_REP_LOCAL_QPN_OFFSET 12
 #define CM_REP_LOCAL_QPN_MASK GENMASK(23, 0)

Such format will allow us to use same GET/SET macros for all
be16/be32 variables and bitfields too.

Separate wire protocol from kernel logic by special GET/SET macros.

Signed-off-by: Leon Romanovsky <leonro@xxxxxxxxxxxx>
---
 drivers/infiniband/core/cm_msgs.h | 71 +++++++++++++++++++++++++++++++
 1 file changed, 71 insertions(+)

diff --git a/drivers/infiniband/core/cm_msgs.h b/drivers/infiniband/core/cm_msgs.h
index 92d7260ac913..99e35a4610f1 100644
--- a/drivers/infiniband/core/cm_msgs.h
+++ b/drivers/infiniband/core/cm_msgs.h
@@ -8,6 +8,7 @@
 #ifndef CM_MSGS_H
 #define CM_MSGS_H
 
+#include <linux/bitfield.h>
 #include <rdma/ib_mad.h>
 #include <rdma/ib_cm.h>
 
@@ -17,6 +18,76 @@
  */
 
 #define IB_CM_CLASS_VERSION	2 /* IB specification 1.2 */
+#define _CM_SET(p, offset, mask, value)                                        \
+	({                                                                     \
+		void *field = (u8 *)p + sizeof(struct ib_mad_hdr) + offset;    \
+		u8 bytes =                                                     \
+			DIV_ROUND_UP(__builtin_popcount(mask), BITS_PER_BYTE); \
+		switch (bytes) {                                               \
+		case 1: {                                                      \
+			*(u8 *)field &= ~mask;                                 \
+			*(u8 *)field |= FIELD_PREP(mask, value);               \
+		} break;                                                       \
+		case 2: {                                                      \
+			u16 val = ntohs(*(__be16 *)field) & ~mask;             \
+			val |= FIELD_PREP(mask, value);                        \
+			*(__be16 *)field = htons(val);                         \
+		} break;                                                       \
+		case 3: {                                                      \
+			u32 val = ntohl(*(__be32 *)field) & ~(mask << 8);      \
+			val |= FIELD_PREP(mask, value) << 8;                   \
+			*(__be32 *)field = htonl(val);                         \
+		} break;                                                       \
+		default: {                                                     \
+			u32 val = ntohl(*(__be32 *)field) & ~mask;             \
+			val |= FIELD_PREP(mask, value);                        \
+			*(__be32 *)field = htonl(val);                         \
+		} break;                                                       \
+		}                                                              \
+	})
+#define CM_SET(field, p, value)                                                \
+	_CM_SET(p, CM_##field##_OFFSET, CM_##field##_MASK, value)
+#define CM_SET64(field, p, value)                                              \
+	({                                                                     \
+		_CM_SET(p, CM_##field##_OFFSET,                                \
+			lower_32_bits(CM_##field##_MASK),                      \
+			lower_32_bits(value));                                 \
+		_CM_SET(p, CM_##field##_OFFSET + sizeof(__be32),               \
+			upper_32_bits(CM_##field##_MASK),                      \
+			upper_32_bits(value));                                 \
+	})
+
+#define _CM_GET(p, offset, mask)                                               \
+	({                                                                     \
+		void *field = (u8 *)p + sizeof(struct ib_mad_hdr) + offset;    \
+		u8 bytes =                                                     \
+			DIV_ROUND_UP(__builtin_popcount(mask), BITS_PER_BYTE); \
+		u32 ret;                                                       \
+		switch (bytes) {                                               \
+		case 1:                                                        \
+			ret = FIELD_GET(mask, *(u8 *)field);                   \
+			break;                                                 \
+		case 2:                                                        \
+			ret = FIELD_GET(mask, ntohs(*(__be16 *)field));        \
+			break;                                                 \
+		case 3:                                                        \
+			ret = FIELD_GET(mask, ntohl(*(__be32 *)field) >> 8);   \
+			break;                                                 \
+		default:                                                       \
+			ret = FIELD_GET(mask, ntohl(*(__be32 *)field));        \
+		}                                                              \
+		ret;                                                           \
+	})
+
+#define CM_GET(field, p) _CM_GET(p, CM_##field##_OFFSET, CM_##field##_MASK)
+#define CM_GET64(field, p)                                                     \
+	({                                                                     \
+		u64 a = _CM_GET(p, CM_##field##_OFFSET,                        \
+				lower_32_bits(CM_##field##_MASK));             \
+		u64 b = _CM_GET(p, CM_##field##_OFFSET + sizeof(__be32),       \
+				upper_32_bits(CM_##field##_MASK));             \
+		a | (b << 32);                                                 \
+	})
 
 struct cm_req_msg {
 	struct ib_mad_hdr hdr;
-- 
2.20.1




[Index of Archives]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Photo]     [Yosemite News]     [Yosemite Photos]     [Linux Kernel]     [Linux SCSI]     [XFree86]

  Powered by Linux