summaryrefslogtreecommitdiff
path: root/usr/src/uts/common/sys/ib/adapters/hermon/hermon_event.h
blob: 450395796ba2393a13d1eea4a3f59fff984b5341 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License (the "License").
 * You may not use this file except in compliance with the License.
 *
 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
 * or http://www.opensolaris.org/os/licensing.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
 * If applicable, add the following below this CDDL HEADER, with the
 * fields enclosed by brackets "[]" replaced with your own identifying
 * information: Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 */

/*
 * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
 */

#ifndef	_SYS_IB_ADAPTERS_HERMON_EVENT_H
#define	_SYS_IB_ADAPTERS_HERMON_EVENT_H

/*
 * hermon_event.h
 *    Contains all of the prototypes, #defines, and structures necessary
 *    for the Interrupt and Event Processing routines
 *    Specifically it contains the various event types, event flags,
 *    structures used for managing Hermon event queues, and prototypes for
 *    many of the functions consumed by other parts of the Hermon driver.
 */

#include <sys/types.h>
#include <sys/conf.h>
#include <sys/ddi.h>
#include <sys/sunddi.h>

#ifdef __cplusplus
extern "C" {
#endif

/*
 * Hermon UAR Doorbell Write Macro - writes UAR registers
 *
 * If on a 32-bit system, we must hold a lock around the ddi_put64() to
 * ensure that the 64-bit write is an atomic operation.  This is a
 * requirement of the Hermon hardware and is to protect from the race
 * condition present when more than one kernel thread attempts to do each
 * of their two 32-bit accesses (for 64-bit doorbell) simultaneously.
 *
 * If we are on a 64-bit system then the ddi_put64() is completed as one
 * 64-bit instruction, and the lock is not needed.
 *
 * This is done as a preprocessor #if to speed up execution at run-time
 * since doorbell ringing is a "fast-path" operation.
 */
#if (DATAMODEL_NATIVE == DATAMODEL_ILP32)
#define	HERMON_UAR_DOORBELL(state, uarhdl, hs_uar, doorbell)	{	\
	mutex_enter(&state->hs_uar_lock);				\
	ddi_put64(uarhdl, hs_uar, doorbell);				\
	mutex_exit(&state->hs_uar_lock);				\
}
#else
#define	HERMON_UAR_DOORBELL(state, uarhdl, hs_uar, doorbell)	{	\
	ddi_put64(uarhdl, hs_uar, doorbell);				\
}
#endif

/*
 * HERMON Doorbell Record (DBr) Write Macro - writes doorbell record in memory
 *
 * Since the DBr is only 32 bits at a time, this can be just a put32, not
 * put64.
 */

#define	HERMON_UAR_DB_RECORD_WRITE(db_addr, dbr)			\
	*(uint32_t *)(db_addr) = htonl(dbr)

/*
 * The following defines specify the default number of Event Queues (EQ) and
 * their default size.  By default the size of each EQ is set to 8K entries,
 * but this value is controllable through the "cp_log_eq_sz" configuration
 * variable.  We also specify the number of EQs which the Arbel driver
 * currently uses (HERMON_NUM_EQ_USED).  Note: this value should be less than
 * or equal to HERMON_NUM_EQ.
 * HERMON:  will limit to 4 total - in anticipation of VMM implementation
 *    logical Eq (0)-catastrophic,
 *		 (1)-error completions,
 *		 (2)-misc events and
 *		 (3)-completions
 */

#define	HERMON_NUM_EQ_SHIFT		0x9 /* hermon has 512 EQs available */
#define	HERMON_NUM_EQ			(1 << HERMON_NUM_EQ_SHIFT)

#define	HERMON_NUM_EQ_USED		4  		/* four per domain */
#define	HERMON_DEFAULT_EQ_SZ_SHIFT	0xd		/* 8192 entries/EQ */
#define	HERMON_EQ_CI_MASK		0xFFFFFF 	/* low 24 bits */

/*
 * These are the defines for the Hermon event types.  They are specified by
 * the Hermon PRM.  Below are the "event type masks" in
 * which each event type corresponds to one of the 64-bits in the mask.
 */

/* Note:  In order per PRM listing */
/* Completion Events */
#define	HERMON_EVT_COMPLETION			0x00
/* IB Affiliated Asynch Events */
#define	HERMON_EVT_PATH_MIGRATED		0x01
#define	HERMON_EVT_COMM_ESTABLISHED		0x02
#define	HERMON_EVT_SEND_QUEUE_DRAINED		0x03
#define	HERMON_EVT_SRQ_LAST_WQE_REACHED		0x13
#define	HERMON_EVT_SRQ_LIMIT			0x14
/* QP Affiliated Asynch Event */
#define	HERMON_EVT_CQ_ERRORS			0x04 /* overrun, protection */
#define	HERMON_EVT_LOCAL_WQ_CAT_ERROR		0x05
#define	HERMON_EVT_LOCAL_QPC_CAT_ERROR		0x06
#define	HERMON_EVT_PATH_MIGRATE_FAILED		0x07
#define	HERMON_EVT_INV_REQ_LOCAL_WQ_ERROR	0x10
#define	HERMON_EVT_LOCAL_ACC_VIO_WQ_ERROR	0x11
#define	HERMON_EVT_SRQ_CATASTROPHIC_ERROR	0x12
#define	HERMON_EVT_SPOOF_FAIL			0x16	/* enet only */
/* FEXCH Errors (QP Affiliated) */
#define	HERMON_EVT_FEXCH_ERROR			0x0B

/* Unaffiliated Asynch Events/Errors */
#define	HERMON_EVT_PORT_STATE_CHANGE		0x09
#define	HERMON_EVT_GPIO				0x15
/* Command Interface */
#define	HERMON_EVT_COMMAND_INTF_COMP		0x0A
/* Miscellaneous */
#define	HERMON_EVT_LOCAL_CAT_ERROR		0x08


#define	HERMON_EVT_MSK_COMPLETION		\
	(1 << HERMON_EVT_COMPLETION)

#define	HERMON_EVT_MSK_PATH_MIGRATED		\
	(1 << HERMON_EVT_PATH_MIGRATED)
#define	HERMON_EVT_MSK_COMM_ESTABLISHED		\
	(1 << HERMON_EVT_COMM_ESTABLISHED)
#define	HERMON_EVT_MSK_SEND_QUEUE_DRAINED	\
	(1 << HERMON_EVT_SEND_QUEUE_DRAINED)
#define	HERMON_EVT_MSK_SRQ_LAST_WQE_REACHED	\
	(1 << HERMON_EVT_SRQ_LAST_WQE_REACHED)
#define	HERMON_EVT_MSK_SRQ_LIMIT		\
	(1 << HERMON_EVT_SRQ_LIMIT)

#define	HERMON_EVT_MSK_CQ_ERRORS		\
	(1 << HERMON_EVT_CQ_ERRORS)
#define	HERMON_EVT_MSK_LOCAL_WQ_CAT_ERROR	\
	(1 << HERMON_EVT_LOCAL_WQ_CAT_ERROR)
#define	HERMON_EVT_MSK_LOCAL_QPC_CAT_ERROR	\
	(1 << HERMON_EVT_LOCAL_QPC_CAT_ERROR)
#define	HERMON_EVT_MSK_PATH_MIGRATE_FAILED	\
	(1 << HERMON_EVT_PATH_MIGRATE_FAILED)
#define	HERMON_EVT_MSK_INV_REQ_LOCAL_WQ_ERROR	\
	(1 << HERMON_EVT_INV_REQ_LOCAL_WQ_ERROR)
#define	HERMON_EVT_MSK_LOCAL_ACC_VIO_WQ_ERROR	\
	(1 << HERMON_EVT_LOCAL_ACC_VIO_WQ_ERROR)
#define	HERMON_EVT_MSK_SRQ_CATASTROPHIC_ERROR	\
	(1 << HERMON_EVT_SRQ_CATASTROPHIC_ERROR)
#define	HERMON_EVT_MSK_SPOOF_FAIL		\
	(1 << HERMON_EVT_SPOOF_FAIL)

#define	HERMON_EVT_MSK_FEXCH_ERROR		\
	(1 << HERMON_EVT_FEXCH_ERROR)

#define	HERMON_EVT_MSK_PORT_STATE_CHANGE	\
	(1 << HERMON_EVT_PORT_STATE_CHANGE)
#define	HERMON_EVT_MSK_GPIO			\
	(1 << HERMON_EVT_GPIO)

#define	HERMON_EVT_MSK_COMMAND_INTF_COMP	\
	(1 << HERMON_EVT_COMMAND_INTF_COMP)

#define	HERMON_EVT_MSK_LOCAL_CAT_ERROR		\
	(1 << HERMON_EVT_LOCAL_CAT_ERROR)


#define	HERMON_EVT_NO_MASK			0

/* For now, "catchall" is just HERMON_EVT_LOCAL_QPC_CAT_ERROR. */
#define	HERMON_EVT_CATCHALL_MASK		0x0040

/*
 * The last defines are used by hermon_eqe_sync() to indicate whether or not
 * to force a DMA sync.  The case for forcing a DMA sync on a EQE comes from
 * the possibility that we could receive an interrupt, read of the ECR, and
 * have each of these operations complete successfully _before_ the hardware
 * has finished its DMA to the event queue.
 */
#define	HERMON_EQ_SYNC_NORMAL			0x0
#define	HERMON_EQ_SYNC_FORCE			0x1

/*
 * Catastrophic error values.  In case of a catastrophic error, the following
 * errors are reported in a special buffer space.  The buffer location is
 * returned from a QUERY_FW command.  We check that buffer against these error
 * values to determine what kind of error occurred.
 */
#define	HERMON_CATASTROPHIC_INTERNAL_ERROR		0x0
#define	HERMON_CATASTROPHIC_UPLINK_BUS_ERROR	0x3
#define	HERMON_CATASTROPHIC_INTERNAL_PARITY_ERROR	0x5
/* Presumably, this is no longer supported */
#define	HERMON_CATASTROPHIC_DDR_DATA_ERROR		0x4

/*
 * This define is the 'enable' flag used when programming the MSI number
 * into event queues.  It is or'd with the MSI number and the result is
 * written into the EX context.
 */

#define	HERMON_EQ_MSI_ENABLE_FLAG	0x200  /* bit 9 of 0x14 in EQC */

/*
 * The following#defines are for the EQ's in the UAR pages.  In Hermon, the
 * arm mechanism is new - in the first 128 (that is, 0 - 127) UAR pages, which
 * are reserved, the only useful thing is the EQ registers.  In turn those
 * locations are ignored in any other UAR page.
 *
 * The driver writes to the with the MSB bit set to arm it, and the current
 * CI (consumer index).
 */
#define	G_EQ0		0x0800
#define	G_EQ1		0x0808
#define	G_EQ2		0x0810
#define	G_EQ3		0x0818

/*
 * They should be written as a 32-bit entity:
 * bit 31:  Arm (if set)
 * bit 23:0 Consumer Index
 */
#define	EQ_ARM_BIT	0x80000000

/*
 * The register to be written is:
 * 	(EQ_num / 4) == UAR page
 *	(EQ_NUM % 4) == G_EQx
 */

#define	ARM_EQ_INDEX(eq) \
	(((eq >> 2) * PAGESIZE) + (0x0800 + ((eq & 0x03) * 0x08)))


/*
 * The hermon_sw_eq_s structure is also referred to using the "hermon_eqhdl_t"
 * typedef (see hermon_typedef.h).  It encodes all the information necessary
 * to track the various resources needed to allocate, initialize, poll, and
 * (later) free an event queue (EQ).
 *
 * Specifically, it has a consumer index and a lock to ensure single threaded
 * access to it.  It has pointers to the various resources allocated for the
 * event queue, i.e. an EQC resource and the memory for the event queue
 * itself.  It has flags to indicate which type of event class(es) the EQ
 * has been mapped to (eq_evttypemask).
 *
 * It also has a pointer to the associated MR handle (for the mapped queue
 * memory) and a function pointer that points to the handler that should
 * be called when the corresponding EQ has fired.  Note: the "eq_func"
 * handler takes a Hermon softstate pointer, a pointer to the EQ handle, and a
 * pointer to a generic hermon_hw_eqe_t structure.  It is up to the "eq_func"
 * handler function to determine what specific type of event is being passed.
 *
 * Lastly, we have the always necessary backpointer to the resource for the
 * EQ handle structure itself.
 */
struct hermon_sw_eq_s {
	uint32_t		eq_consindx;
	uint32_t		eq_eqnum;
	hermon_hw_eqe_t		*eq_buf;
	uint32_t		*eq_doorbell;
	hermon_mrhdl_t		eq_mrhdl;
	uint32_t		eq_bufsz;
	uint32_t		eq_log_eqsz;
	uint_t			eq_evttypemask;
	hermon_rsrc_t		*eq_eqcrsrcp;
	hermon_rsrc_t		*eq_rsrcp;
	int (*eq_func)(hermon_state_t *state, hermon_eqhdl_t eq,
	    hermon_hw_eqe_t *eqe);

	struct hermon_qalloc_info_s eq_eqinfo;
};

int hermon_eq_init_all(hermon_state_t *state);
int hermon_eq_fini_all(hermon_state_t *state);
int hermon_eq_arm_all(hermon_state_t *state);
uint_t hermon_isr(caddr_t arg1, caddr_t arg2);
void hermon_eq_doorbell(hermon_state_t *state, uint32_t eq_cmd, uint32_t eqn,
    uint32_t eq_param);
void hermon_eq_overflow_handler(hermon_state_t *state, hermon_eqhdl_t eq,
    hermon_hw_eqe_t *eqe);
void hermon_eq_reset_uar_baseaddr(hermon_state_t *state);

#ifdef __cplusplus
}
#endif

#endif	/* _SYS_IB_ADAPTERS_HERMON_EVENT_H */