浏览代码

Separated out to a clean new drivers/infiniband directory.

tags/v0.9.3
Michael Brown 16 年前
父节点
当前提交
982e4dd101
共有 5 个文件被更改,包括 6259 次插入5 次删除
  1. 1
    5
      src/Makefile
  2. 3460
    0
      src/drivers/infiniband/MT25218_PRM.h
  3. 2130
    0
      src/drivers/infiniband/arbel.c
  4. 459
    0
      src/drivers/infiniband/arbel.h
  5. 209
    0
      src/drivers/infiniband/mlx_bitops.h

+ 1
- 5
src/Makefile 查看文件

@@ -152,6 +152,7 @@ SRCDIRS		+= drivers/scsi
152 152
 SRCDIRS		+= drivers/ata
153 153
 SRCDIRS		+= drivers/nvs
154 154
 SRCDIRS		+= drivers/bitbash
155
+SRCDIRS		+= drivers/infiniband
155 156
 SRCDIRS		+= interface/pxe
156 157
 SRCDIRS		+= tests
157 158
 SRCDIRS		+= crypto crypto/axtls crypto/matrixssl
@@ -165,11 +166,6 @@ SRCDIRS		+= usr
165 166
 NON_AUTO_SRCS	+= core/elf_loader.c
166 167
 NON_AUTO_SRCS	+= drivers/net/prism2.c
167 168
 
168
-SRCS		+= drivers/net/mlx_ipoib/mt25218.c
169
-SRCS		+= drivers/net/mlx_ipoib/mt23108.c
170
-CFLAGS_mt25218	= -Wno-error
171
-CFLAGS_mt23108	= -Wno-error
172
-
173 169
 # Rules for finalising files.  TGT_MAKEROM_FLAGS is defined as part of
174 170
 # the automatic build system and varies by target; it includes the
175 171
 # "-p 0x1234,0x5678" string to set the PCI IDs.

+ 3460
- 0
src/drivers/infiniband/MT25218_PRM.h
文件差异内容过多而无法显示
查看文件


+ 2130
- 0
src/drivers/infiniband/arbel.c
文件差异内容过多而无法显示
查看文件


+ 459
- 0
src/drivers/infiniband/arbel.h 查看文件

@@ -0,0 +1,459 @@
1
+#ifndef _ARBEL_H
2
+#define _ARBEL_H
3
+
4
+/** @file
5
+ *
6
+ * Mellanox Arbel Infiniband HCA driver
7
+ *
8
+ */
9
+
10
+#include <stdint.h>
11
+#include <gpxe/uaccess.h>
12
+#include "mlx_bitops.h"
13
+#include "MT25218_PRM.h"
14
+
15
+/*
16
+ * Hardware constants
17
+ *
18
+ */
19
+
20
+/* PCI BARs */
21
+#define ARBEL_PCI_CONFIG_BAR		PCI_BASE_ADDRESS_0
22
+#define ARBEL_PCI_CONFIG_BAR_SIZE	0x100000
23
+#define ARBEL_PCI_UAR_BAR		PCI_BASE_ADDRESS_2
24
+#define ARBEL_PCI_UAR_IDX		1
25
+#define ARBEL_PCI_UAR_SIZE		0x1000
26
+
27
+/* UAR context table (UCE) resource types */
28
+#define ARBEL_UAR_RES_NONE		0x00
29
+#define ARBEL_UAR_RES_CQ_CI		0x01
30
+#define ARBEL_UAR_RES_CQ_ARM		0x02
31
+#define ARBEL_UAR_RES_SQ		0x03
32
+#define ARBEL_UAR_RES_RQ		0x04
33
+#define ARBEL_UAR_RES_GROUP_SEP		0x07
34
+
35
+/* Work queue entry and completion queue entry opcodes */
36
+#define ARBEL_OPCODE_SEND		0x0a
37
+#define ARBEL_OPCODE_RECV_ERROR		0xfe
38
+#define ARBEL_OPCODE_SEND_ERROR		0xff
39
+
40
+/* HCA command register opcodes */
41
+#define ARBEL_HCR_QUERY_DEV_LIM		0x0003
42
+#define ARBEL_HCR_QUERY_FW		0x0004
43
+#define ARBEL_HCR_INIT_HCA		0x0007
44
+#define ARBEL_HCR_CLOSE_HCA		0x0008
45
+#define ARBEL_HCR_INIT_IB		0x0009
46
+#define ARBEL_HCR_CLOSE_IB		0x000a
47
+#define ARBEL_HCR_SW2HW_MPT		0x000d
48
+#define ARBEL_HCR_MAP_EQ		0x0012
49
+#define ARBEL_HCR_SW2HW_EQ		0x0013
50
+#define ARBEL_HCR_HW2SW_EQ		0x0014
51
+#define ARBEL_HCR_SW2HW_CQ		0x0016
52
+#define ARBEL_HCR_HW2SW_CQ		0x0017
53
+#define ARBEL_HCR_RST2INIT_QPEE		0x0019
54
+#define ARBEL_HCR_INIT2RTR_QPEE		0x001a
55
+#define ARBEL_HCR_RTR2RTS_QPEE		0x001b
56
+#define ARBEL_HCR_2RST_QPEE		0x0021
57
+#define ARBEL_HCR_MAD_IFC		0x0024
58
+#define ARBEL_HCR_READ_MGM		0x0025
59
+#define ARBEL_HCR_WRITE_MGM		0x0026
60
+#define ARBEL_HCR_MGID_HASH		0x0027
61
+#define ARBEL_HCR_RUN_FW		0x0ff6
62
+#define ARBEL_HCR_DISABLE_LAM		0x0ff7
63
+#define ARBEL_HCR_ENABLE_LAM		0x0ff8
64
+#define ARBEL_HCR_UNMAP_ICM		0x0ff9
65
+#define ARBEL_HCR_MAP_ICM		0x0ffa
66
+#define ARBEL_HCR_UNMAP_ICM_AUX		0x0ffb
67
+#define ARBEL_HCR_MAP_ICM_AUX		0x0ffc
68
+#define ARBEL_HCR_SET_ICM_SIZE		0x0ffd
69
+#define ARBEL_HCR_UNMAP_FA		0x0ffe
70
+#define ARBEL_HCR_MAP_FA		0x0fff
71
+
72
+/* Service types */
73
+#define ARBEL_ST_UD			0x03
74
+
75
+/* MTUs */
76
+#define ARBEL_MTU_2048			0x04
77
+
78
+#define ARBEL_NO_EQ			64
79
+
80
+#define ARBEL_INVALID_LKEY		0x00000100UL
81
+
82
+#define ARBEL_DB_POST_SND_OFFSET	0x10
83
+
84
+/*
85
+ * Datatypes that seem to be missing from the autogenerated documentation
86
+ *
87
+ */
88
+struct arbelprm_mgm_hash_st {
89
+	pseudo_bit_t reserved0[0x00020];
90
+/* -------------- */
91
+	pseudo_bit_t hash[0x00010];
92
+	pseudo_bit_t reserved1[0x00010];
93
+} __attribute__ (( packed ));
94
+
95
+struct arbelprm_scalar_parameter_st {
96
+	pseudo_bit_t reserved0[0x00020];
97
+/* -------------- */
98
+	pseudo_bit_t value[0x00020];
99
+} __attribute__ (( packed ));
100
+
101
+/*
102
+ * Wrapper structures for hardware datatypes
103
+ *
104
+ */
105
+
106
+struct MLX_DECLARE_STRUCT ( arbelprm_access_lam );
107
+struct MLX_DECLARE_STRUCT ( arbelprm_completion_queue_context );
108
+struct MLX_DECLARE_STRUCT ( arbelprm_completion_queue_entry );
109
+struct MLX_DECLARE_STRUCT ( arbelprm_completion_with_error );
110
+struct MLX_DECLARE_STRUCT ( arbelprm_cq_arm_db_record );
111
+struct MLX_DECLARE_STRUCT ( arbelprm_cq_ci_db_record );
112
+struct MLX_DECLARE_STRUCT ( arbelprm_eqc );
113
+struct MLX_DECLARE_STRUCT ( arbelprm_hca_command_register );
114
+struct MLX_DECLARE_STRUCT ( arbelprm_init_hca );
115
+struct MLX_DECLARE_STRUCT ( arbelprm_init_ib );
116
+struct MLX_DECLARE_STRUCT ( arbelprm_mad_ifc );
117
+struct MLX_DECLARE_STRUCT ( arbelprm_mgm_entry );
118
+struct MLX_DECLARE_STRUCT ( arbelprm_mgm_hash );
119
+struct MLX_DECLARE_STRUCT ( arbelprm_mpt );
120
+struct MLX_DECLARE_STRUCT ( arbelprm_qp_db_record );
121
+struct MLX_DECLARE_STRUCT ( arbelprm_qp_ee_state_transitions );
122
+struct MLX_DECLARE_STRUCT ( arbelprm_query_dev_lim );
123
+struct MLX_DECLARE_STRUCT ( arbelprm_query_fw );
124
+struct MLX_DECLARE_STRUCT ( arbelprm_queue_pair_ee_context_entry );
125
+struct MLX_DECLARE_STRUCT ( arbelprm_recv_wqe_segment_next );
126
+struct MLX_DECLARE_STRUCT ( arbelprm_scalar_parameter );
127
+struct MLX_DECLARE_STRUCT ( arbelprm_send_doorbell );
128
+struct MLX_DECLARE_STRUCT ( arbelprm_ud_address_vector );
129
+struct MLX_DECLARE_STRUCT ( arbelprm_virtual_physical_mapping );
130
+struct MLX_DECLARE_STRUCT ( arbelprm_wqe_segment_ctrl_send );
131
+struct MLX_DECLARE_STRUCT ( arbelprm_wqe_segment_data_ptr );
132
+struct MLX_DECLARE_STRUCT ( arbelprm_wqe_segment_next );
133
+struct MLX_DECLARE_STRUCT ( arbelprm_wqe_segment_ud );
134
+
135
+/*
136
+ * Composite hardware datatypes
137
+ *
138
+ */
139
+
140
+#define ARBEL_MAX_GATHER 1
141
+
142
+struct arbelprm_ud_send_wqe {
143
+	struct arbelprm_wqe_segment_next next;
144
+	struct arbelprm_wqe_segment_ctrl_send ctrl;
145
+	struct arbelprm_wqe_segment_ud ud;
146
+	struct arbelprm_wqe_segment_data_ptr data[ARBEL_MAX_GATHER];
147
+} __attribute__ (( packed ));
148
+
149
+#define ARBEL_MAX_SCATTER 1
150
+
151
+struct arbelprm_recv_wqe {
152
+	/* The autogenerated header is inconsistent between send and
153
+	 * receive WQEs.  The "ctrl" structure for receive WQEs is
154
+	 * defined to include the "next" structure.  Since the "ctrl"
155
+	 * part of the "ctrl" structure contains only "reserved, must
156
+	 * be zero" bits, we ignore its definition and provide
157
+	 * something more usable.
158
+	 */
159
+	struct arbelprm_recv_wqe_segment_next next;
160
+	uint32_t ctrl[2]; /* All "reserved, must be zero" */
161
+	struct arbelprm_wqe_segment_data_ptr data[ARBEL_MAX_SCATTER];
162
+} __attribute__ (( packed ));
163
+
164
+union arbelprm_completion_entry {
165
+	struct arbelprm_completion_queue_entry normal;
166
+	struct arbelprm_completion_with_error error;
167
+} __attribute__ (( packed ));
168
+
169
+union arbelprm_doorbell_record {
170
+	struct arbelprm_cq_arm_db_record cq_arm;
171
+	struct arbelprm_cq_ci_db_record cq_ci;
172
+	struct arbelprm_qp_db_record qp;
173
+} __attribute__ (( packed ));
174
+
175
+union arbelprm_doorbell_register {
176
+	struct arbelprm_send_doorbell send;
177
+	uint32_t dword[2];
178
+} __attribute__ (( packed ));
179
+
180
+union arbelprm_mad {
181
+	struct arbelprm_mad_ifc ifc;
182
+	union ib_mad mad;
183
+} __attribute__ (( packed ));
184
+
185
+/*
186
+ * gPXE-specific definitions
187
+ *
188
+ */
189
+
190
+/** Arbel device limits */
191
+struct arbel_dev_limits {
192
+	/** Number of reserved QPs */
193
+	unsigned int reserved_qps;
194
+	/** QP context entry size */
195
+	size_t qpc_entry_size;
196
+	/** Extended QP context entry size */
197
+	size_t eqpc_entry_size;
198
+	/** Number of reserved SRQs */
199
+	unsigned int reserved_srqs;
200
+	/** SRQ context entry size */
201
+	size_t srqc_entry_size;
202
+	/** Number of reserved EEs */
203
+	unsigned int reserved_ees;
204
+	/** EE context entry size */
205
+	size_t eec_entry_size;
206
+	/** Extended EE context entry size */
207
+	size_t eeec_entry_size;
208
+	/** Number of reserved CQs */
209
+	unsigned int reserved_cqs;
210
+	/** CQ context entry size */
211
+	size_t cqc_entry_size;
212
+	/** Number of reserved MTTs */
213
+	unsigned int reserved_mtts;
214
+	/** MTT entry size */
215
+	size_t mtt_entry_size;
216
+	/** Number of reserved MRWs */
217
+	unsigned int reserved_mrws;
218
+	/** MPT entry size */
219
+	size_t mpt_entry_size;
220
+	/** Number of reserved RDBs */
221
+	unsigned int reserved_rdbs;
222
+	/** EQ context entry size */
223
+	size_t eqc_entry_size;
224
+	/** Number of reserved UARs */
225
+	unsigned int reserved_uars;
226
+};
227
+
228
+/** Alignment of Arbel send work queue entries */
229
+#define ARBEL_SEND_WQE_ALIGN 128
230
+
231
+/** An Arbel send work queue entry */
232
+union arbel_send_wqe {
233
+	struct arbelprm_ud_send_wqe ud;
234
+	uint8_t force_align[ARBEL_SEND_WQE_ALIGN];
235
+} __attribute__ (( packed ));
236
+
237
+/** An Arbel send work queue */
238
+struct arbel_send_work_queue {
239
+	/** Doorbell record number */
240
+	unsigned int doorbell_idx;
241
+	/** Work queue entries */
242
+	union arbel_send_wqe *wqe;
243
+	/** Size of work queue */
244
+	size_t wqe_size;
245
+};
246
+
247
+/** Alignment of Arbel receive work queue entries */
248
+#define ARBEL_RECV_WQE_ALIGN 64
249
+
250
+/** An Arbel receive work queue entry */
251
+union arbel_recv_wqe {
252
+	struct arbelprm_recv_wqe recv;
253
+	uint8_t force_align[ARBEL_RECV_WQE_ALIGN];
254
+} __attribute__ (( packed ));
255
+
256
+/** An Arbel receive work queue */
257
+struct arbel_recv_work_queue {
258
+	/** Doorbell record number */
259
+	unsigned int doorbell_idx;
260
+	/** Work queue entries */
261
+	union arbel_recv_wqe *wqe;
262
+	/** Size of work queue */
263
+	size_t wqe_size;
264
+};
265
+
266
+/** Maximum number of allocatable queue pairs
267
+ *
268
+ * This is a policy decision, not a device limit.
269
+ */
270
+#define ARBEL_MAX_QPS		8
271
+
272
+/** Base queue pair number */
273
+#define ARBEL_QPN_BASE 0x550000
274
+
275
+/** An Arbel queue pair */
276
+struct arbel_queue_pair {
277
+	/** Send work queue */
278
+	struct arbel_send_work_queue send;
279
+	/** Receive work queue */
280
+	struct arbel_recv_work_queue recv;
281
+};
282
+
283
+/** Maximum number of allocatable completion queues
284
+ *
285
+ * This is a policy decision, not a device limit.
286
+ */
287
+#define ARBEL_MAX_CQS		8
288
+
289
+/** An Arbel completion queue */
290
+struct arbel_completion_queue {
291
+	/** Consumer counter doorbell record number */
292
+	unsigned int ci_doorbell_idx;
293
+	/** Arm queue doorbell record number */
294
+	unsigned int arm_doorbell_idx;
295
+	/** Completion queue entries */
296
+	union arbelprm_completion_entry *cqe;
297
+	/** Size of completion queue */
298
+	size_t cqe_size;
299
+};
300
+
301
+/** An Arbel resource bitmask */
302
+typedef uint32_t arbel_bitmask_t;
303
+
304
+/** Size of an Arbel resource bitmask */
305
+#define ARBEL_BITMASK_SIZE(max_entries)					     \
306
+	( ( (max_entries) + ( 8 * sizeof ( arbel_bitmask_t ) ) - 1 ) /	     \
307
+	  ( 8 * sizeof ( arbel_bitmask_t ) ) )
308
+
309
+/** An Arbel device */
310
+struct arbel {
311
+	/** PCI configuration registers */
312
+	void *config;
313
+	/** PCI user Access Region */
314
+	void *uar;
315
+
316
+	/** Command input mailbox */
317
+	void *mailbox_in;
318
+	/** Command output mailbox */
319
+	void *mailbox_out;
320
+
321
+	/** Firmware area in external memory */
322
+	userptr_t firmware_area;
323
+	/** ICM size */
324
+	size_t icm_len;
325
+	/** ICM AUX size */
326
+	size_t icm_aux_len;
327
+	/** ICM area */
328
+	userptr_t icm;
329
+
330
+	/** Doorbell records */
331
+	union arbelprm_doorbell_record *db_rec;
332
+	/** Reserved LKey
333
+	 *
334
+	 * Used to get unrestricted memory access.
335
+	 */
336
+	unsigned long reserved_lkey;
337
+
338
+	/** Completion queue in-use bitmask */
339
+	arbel_bitmask_t cq_inuse[ ARBEL_BITMASK_SIZE ( ARBEL_MAX_CQS ) ];
340
+	/** Queue pair in-use bitmask */
341
+	arbel_bitmask_t qp_inuse[ ARBEL_BITMASK_SIZE ( ARBEL_MAX_QPS ) ];
342
+	
343
+	/** Device limits */
344
+	struct arbel_dev_limits limits;
345
+};
346
+
347
+/** Global protection domain */
348
+#define ARBEL_GLOBAL_PD			0x123456
349
+
350
+/** Memory key prefix */
351
+#define ARBEL_MKEY_PREFIX		0x77000000UL
352
+
353
+/*
354
+ * HCA commands
355
+ *
356
+ */
357
+
358
+#define ARBEL_HCR_BASE			0x80680
359
+#define ARBEL_HCR_REG(x)		( ARBEL_HCR_BASE + 4 * (x) )
360
+#define ARBEL_HCR_MAX_WAIT_MS		2000
361
+#define ARBEL_MBOX_ALIGN		4096
362
+#define ARBEL_MBOX_SIZE			512
363
+
364
+/* HCA command is split into
365
+ *
366
+ * bits  11:0	Opcode
367
+ * bit     12	Input uses mailbox
368
+ * bit     13	Output uses mailbox
369
+ * bits 22:14	Input parameter length (in dwords)
370
+ * bits 31:23	Output parameter length (in dwords)
371
+ *
372
+ * Encoding the information in this way allows us to cut out several
373
+ * parameters to the arbel_command() call.
374
+ */
375
+#define ARBEL_HCR_IN_MBOX		0x00001000UL
376
+#define ARBEL_HCR_OUT_MBOX		0x00002000UL
377
+#define ARBEL_HCR_OPCODE( _command )	( (_command) & 0xfff )
378
+#define ARBEL_HCR_IN_LEN( _command )	( ( (_command) >> 12 ) & 0x7fc )
379
+#define ARBEL_HCR_OUT_LEN( _command )	( ( (_command) >> 21 ) & 0x7fc )
380
+
381
+/** Build HCR command from component parts */
382
+#define ARBEL_HCR_INOUT_CMD( _opcode, _in_mbox, _in_len,		     \
383
+			     _out_mbox, _out_len )			     \
384
+	( (_opcode) |							     \
385
+	  ( (_in_mbox) ? ARBEL_HCR_IN_MBOX : 0 ) |			     \
386
+	  ( ( (_in_len) / 4 ) << 14 ) |					     \
387
+	  ( (_out_mbox) ? ARBEL_HCR_OUT_MBOX : 0 ) |			     \
388
+	  ( ( (_out_len) / 4 ) << 23 ) )
389
+
390
+#define ARBEL_HCR_IN_CMD( _opcode, _in_mbox, _in_len )			     \
391
+	ARBEL_HCR_INOUT_CMD ( _opcode, _in_mbox, _in_len, 0, 0 )
392
+
393
+#define ARBEL_HCR_OUT_CMD( _opcode, _out_mbox, _out_len )		     \
394
+	ARBEL_HCR_INOUT_CMD ( _opcode, 0, 0, _out_mbox, _out_len )
395
+
396
+#define ARBEL_HCR_VOID_CMD( _opcode )					     \
397
+	ARBEL_HCR_INOUT_CMD ( _opcode, 0, 0, 0, 0 )
398
+
399
+/*
400
+ * Doorbell record allocation
401
+ *
402
+ * The doorbell record map looks like:
403
+ *
404
+ *    ARBEL_MAX_CQS * Arm completion queue doorbell
405
+ *    ARBEL_MAX_QPS * Send work request doorbell
406
+ *    Group separator
407
+ *    ...(empty space)...
408
+ *    ARBEL_MAX_QPS * Receive work request doorbell
409
+ *    ARBEL_MAX_CQS * Completion queue consumer counter update doorbell
410
+ */
411
+
412
+#define ARBEL_MAX_DOORBELL_RECORDS 512
413
+#define ARBEL_GROUP_SEPARATOR_DOORBELL ( ARBEL_MAX_CQS + ARBEL_MAX_QPS )
414
+
415
+/**
416
+ * Get arm completion queue doorbell index
417
+ *
418
+ * @v cqn_offset	Completion queue number offset
419
+ * @ret doorbell_idx	Doorbell index
420
+ */
421
+static inline unsigned int
422
+arbel_cq_arm_doorbell_idx ( unsigned int cqn_offset ) {
423
+	return cqn_offset;
424
+}
425
+
426
+/**
427
+ * Get send work request doorbell index
428
+ *
429
+ * @v qpn_offset	Queue pair number offset
430
+ * @ret doorbell_idx	Doorbell index
431
+ */
432
+static inline unsigned int
433
+arbel_send_doorbell_idx ( unsigned int qpn_offset ) {
434
+	return ( ARBEL_MAX_CQS + qpn_offset );
435
+}
436
+
437
+/**
438
+ * Get receive work request doorbell index
439
+ *
440
+ * @v qpn_offset	Queue pair number offset
441
+ * @ret doorbell_idx	Doorbell index
442
+ */
443
+static inline unsigned int
444
+arbel_recv_doorbell_idx ( unsigned int qpn_offset ) {
445
+	return ( ARBEL_MAX_DOORBELL_RECORDS - ARBEL_MAX_CQS - qpn_offset - 1 );
446
+}
447
+
448
+/**
449
+ * Get completion queue consumer counter doorbell index
450
+ *
451
+ * @v cqn_offset	Completion queue number offset
452
+ * @ret doorbell_idx	Doorbell index
453
+ */
454
+static inline unsigned int
455
+arbel_cq_ci_doorbell_idx ( unsigned int cqn_offset ) {
456
+	return ( ARBEL_MAX_DOORBELL_RECORDS - cqn_offset - 1 );
457
+}
458
+
459
+#endif /* _ARBEL_H */

+ 209
- 0
src/drivers/infiniband/mlx_bitops.h 查看文件

@@ -0,0 +1,209 @@
1
+#ifndef _MLX_BITOPS_H
2
+#define _MLX_BITOPS_H
3
+
4
+/*
5
+ * Copyright (C) 2007 Michael Brown <mbrown@fensystems.co.uk>.
6
+ *
7
+ * This program is free software; you can redistribute it and/or
8
+ * modify it under the terms of the GNU General Public License as
9
+ * published by the Free Software Foundation; either version 2 of the
10
+ * License, or any later version.
11
+ *
12
+ * This program is distributed in the hope that it will be useful, but
13
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
14
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15
+ * General Public License for more details.
16
+ *
17
+ * You should have received a copy of the GNU General Public License
18
+ * along with this program; if not, write to the Free Software
19
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20
+ */
21
+
22
+/**
23
+ * @file
24
+ *
25
+ * Mellanox bit operations
26
+ *
27
+ */
28
+
29
+/* Datatype used to represent a bit in the Mellanox autogenerated headers */
30
+typedef unsigned char pseudo_bit_t;
31
+
32
+/**
33
+ * Wrapper structure for pseudo_bit_t structures
34
+ *
35
+ * This structure provides a wrapper around the autogenerated
36
+ * pseudo_bit_t structures.  It has the correct size, and also
37
+ * encapsulates type information about the underlying pseudo_bit_t
38
+ * structure, which allows the MLX_FILL etc. macros to work without
39
+ * requiring explicit type information.
40
+ */
41
+#define MLX_DECLARE_STRUCT( _structure )				     \
42
+	_structure {							     \
43
+	    union {							     \
44
+		uint8_t bytes[ sizeof ( struct _structure ## _st ) / 8 ];    \
45
+		uint32_t dwords[ sizeof ( struct _structure ## _st ) / 32 ]; \
46
+		struct _structure ## _st *dummy[0];			     \
47
+	    } u;							     \
48
+	}
49
+
50
+/** Get pseudo_bit_t structure type from wrapper structure pointer */
51
+#define MLX_PSEUDO_STRUCT( _ptr )					     \
52
+	typeof ( *((_ptr)->u.dummy[0]) )
53
+
54
+/** Bit offset of a field within a pseudo_bit_t structure */
55
+#define MLX_BIT_OFFSET( _structure_st, _field )				     \
56
+	offsetof ( _structure_st, _field )
57
+
58
+/** Dword offset of a field within a pseudo_bit_t structure */
59
+#define MLX_DWORD_OFFSET( _structure_st, _field )			     \
60
+	( MLX_BIT_OFFSET ( _structure_st, _field ) / 32 )
61
+
62
+/** Dword bit offset of a field within a pseudo_bit_t structure
63
+ *
64
+ * Yes, using mod-32 would work, but would lose the check for the
65
+ * error of specifying a mismatched field name and dword index.
66
+ */
67
+#define MLX_DWORD_BIT_OFFSET( _structure_st, _index, _field )		     \
68
+	( MLX_BIT_OFFSET ( _structure_st, _field ) - ( 32 * (_index) ) )
69
+
70
+/** Bit width of a field within a pseudo_bit_t structure */
71
+#define MLX_BIT_WIDTH( _structure_st, _field )				     \
72
+	sizeof ( ( ( _structure_st * ) NULL )->_field )
73
+
74
+/** Bit mask for a field within a pseudo_bit_t structure */
75
+#define MLX_BIT_MASK( _structure_st, _field )				     \
76
+	( ( ~( ( uint32_t ) 0 ) ) >>					     \
77
+	  ( 32 - MLX_BIT_WIDTH ( _structure_st, _field ) ) )
78
+
79
+/*
80
+ * Assemble native-endian dword from named fields and values
81
+ *
82
+ */
83
+
84
+#define MLX_ASSEMBLE_1( _structure_st, _index, _field, _value )		     \
85
+	( (_value) << MLX_DWORD_BIT_OFFSET ( _structure_st, _index, _field ) )
86
+
87
+#define MLX_ASSEMBLE_2( _structure_st, _index, _field, _value, ... )	     \
88
+	( MLX_ASSEMBLE_1 ( _structure_st, _index, _field, _value ) |	     \
89
+	  MLX_ASSEMBLE_1 ( _structure_st, _index, __VA_ARGS__ ) )
90
+
91
+#define MLX_ASSEMBLE_3( _structure_st, _index, _field, _value, ... )	     \
92
+	( MLX_ASSEMBLE_1 ( _structure_st, _index, _field, _value ) |	     \
93
+	  MLX_ASSEMBLE_2 ( _structure_st, _index, __VA_ARGS__ ) )
94
+
95
+#define MLX_ASSEMBLE_4( _structure_st, _index, _field, _value, ... )	     \
96
+	( MLX_ASSEMBLE_1 ( _structure_st, _index, _field, _value ) |	     \
97
+	  MLX_ASSEMBLE_3 ( _structure_st, _index, __VA_ARGS__ ) )
98
+
99
+#define MLX_ASSEMBLE_5( _structure_st, _index, _field, _value, ... )	     \
100
+	( MLX_ASSEMBLE_1 ( _structure_st, _index, _field, _value ) |	     \
101
+	  MLX_ASSEMBLE_4 ( _structure_st, _index, __VA_ARGS__ ) )
102
+
103
+#define MLX_ASSEMBLE_6( _structure_st, _index, _field, _value, ... )	     \
104
+	( MLX_ASSEMBLE_1 ( _structure_st, _index, _field, _value ) |	     \
105
+	  MLX_ASSEMBLE_5 ( _structure_st, _index, __VA_ARGS__ ) )
106
+
107
+/*
108
+ * Build native-endian (positive) dword bitmasks from named fields
109
+ *
110
+ */
111
+
112
+#define MLX_MASK_1( _structure_st, _index, _field )			     \
113
+	( MLX_BIT_MASK ( _structure_st, _field ) <<			     \
114
+	  MLX_DWORD_BIT_OFFSET ( _structure_st, _index, _field ) )
115
+
116
+#define MLX_MASK_2( _structure_st, _index, _field, ... )		     \
117
+	( MLX_MASK_1 ( _structure_st, _index, _field ) |		     \
118
+	  MLX_MASK_1 ( _structure_st, _index, __VA_ARGS__ ) )
119
+
120
+#define MLX_MASK_3( _structure_st, _index, _field, ... )		     \
121
+	( MLX_MASK_1 ( _structure_st, _index, _field ) |		     \
122
+	  MLX_MASK_2 ( _structure_st, _index, __VA_ARGS__ ) )
123
+
124
+#define MLX_MASK_4( _structure_st, _index, _field, ... )		     \
125
+	( MLX_MASK_1 ( _structure_st, _index, _field ) |		     \
126
+	  MLX_MASK_3 ( _structure_st, _index, __VA_ARGS__ ) )
127
+
128
+#define MLX_MASK_5( _structure_st, _index, _field, ... )		     \
129
+	( MLX_MASK_1 ( _structure_st, _index, _field ) |		     \
130
+	  MLX_MASK_4 ( _structure_st, _index, __VA_ARGS__ ) )
131
+
132
+#define MLX_MASK_6( _structure_st, _index, _field, ... )		     \
133
+	( MLX_MASK_1 ( _structure_st, _index, _field ) |		     \
134
+	  MLX_MASK_5 ( _structure_st, _index, __VA_ARGS__ ) )
135
+
136
+/*
137
+ * Populate big-endian dwords from named fields and values
138
+ *
139
+ */
140
+
141
+#define MLX_FILL( _ptr, _index, _assembled )				     \
142
+	do {								     \
143
+		uint32_t *__ptr = &(_ptr)->u.dwords[(_index)];		     \
144
+		uint32_t __assembled = (_assembled);			     \
145
+		*__ptr = cpu_to_be32 ( __assembled );			     \
146
+	} while ( 0 )
147
+
148
+#define MLX_FILL_1( _ptr, _index, ... )					     \
149
+	MLX_FILL ( _ptr, _index, MLX_ASSEMBLE_1 ( MLX_PSEUDO_STRUCT ( _ptr ),\
150
+						  _index, __VA_ARGS__ ) )
151
+
152
+#define MLX_FILL_2( _ptr, _index, ... )					     \
153
+	MLX_FILL ( _ptr, _index, MLX_ASSEMBLE_2 ( MLX_PSEUDO_STRUCT ( _ptr ),\
154
+						  _index, __VA_ARGS__ ) )
155
+
156
+#define MLX_FILL_3( _ptr, _index, ... )					     \
157
+	MLX_FILL ( _ptr, _index, MLX_ASSEMBLE_3 ( MLX_PSEUDO_STRUCT ( _ptr ),\
158
+						  _index, __VA_ARGS__ ) )
159
+
160
+#define MLX_FILL_4( _ptr, _index, ... )					     \
161
+	MLX_FILL ( _ptr, _index, MLX_ASSEMBLE_4 ( MLX_PSEUDO_STRUCT ( _ptr ),\
162
+						  _index, __VA_ARGS__ ) )
163
+
164
+#define MLX_FILL_5( _ptr, _index, ... )					     \
165
+	MLX_FILL ( _ptr, _index, MLX_ASSEMBLE_5 ( MLX_PSEUDO_STRUCT ( _ptr ),\
166
+						  _index, __VA_ARGS__ ) )
167
+
168
+#define MLX_FILL_6( _ptr, _index, ... )					     \
169
+	MLX_FILL ( _ptr, _index, MLX_ASSEMBLE_6 ( MLX_PSEUDO_STRUCT ( _ptr ),\
170
+						  _index, __VA_ARGS__ ) )
171
+
172
+/*
173
+ * Modify big-endian dword using named field and value
174
+ *
175
+ */
176
+
177
+#define MLX_SET( _ptr, _field, _value )					     \
178
+	do {								     \
179
+		unsigned int __index = 					     \
180
+		    MLX_DWORD_OFFSET ( MLX_PSEUDO_STRUCT ( _ptr ), _field ); \
181
+		uint32_t *__ptr = &(_ptr)->u.dwords[__index];		     \
182
+		uint32_t __value = be32_to_cpu ( *__ptr );		     \
183
+		__value &= ~( MLX_MASK_1 ( MLX_PSEUDO_STRUCT ( _ptr ),	     \
184
+					   __index, _field ) );		     \
185
+		__value |= MLX_ASSEMBLE_1 ( MLX_PSEUDO_STRUCT ( _ptr ),	     \
186
+					    __index, _field, _value );	     \
187
+		*__ptr = cpu_to_be32 ( __value );			     \
188
+	} while ( 0 )
189
+
190
+/*
191
+ * Extract value of named field
192
+ *
193
+ */
194
+
195
+#define MLX_GET( _ptr, _field )						     \
196
+	( {								     \
197
+		unsigned int __index = 					     \
198
+		    MLX_DWORD_OFFSET ( MLX_PSEUDO_STRUCT ( _ptr ), _field ); \
199
+		uint32_t *__ptr = &(_ptr)->u.dwords[__index];		     \
200
+		uint32_t __value = be32_to_cpu ( *__ptr );		     \
201
+		__value >>=						     \
202
+		    MLX_DWORD_BIT_OFFSET ( MLX_PSEUDO_STRUCT ( _ptr ),	     \
203
+					    __index, _field );		     \
204
+		__value &=						     \
205
+		    MLX_BIT_MASK ( MLX_PSEUDO_STRUCT ( _ptr ), _field );     \
206
+		__value;						     \
207
+	} )
208
+
209
+#endif /* _MLX_BITOPS_H */

正在加载...
取消
保存