summaryrefslogtreecommitdiff
path: root/usr/src/uts/i86pc/sys/ioat.h
blob: 685debeab8bfb3a35157c8457494838f8fba9d4c (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
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
/*
 * 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 2009 Sun Microsystems, Inc.  All rights reserved.
 * Use is subject to license terms.
 */

#ifndef _SYS_IOAT_H
#define	_SYS_IOAT_H

#ifdef __cplusplus
extern "C" {
#endif

#include <sys/types.h>
#include <sys/dcopy.h>
#include <sys/dcopy_device.h>


/* ioat ioctls */
#define	IOATIOC			('T'<< 8)
typedef enum {
	IOAT_IOCTL_WRITE_REG	= (IOATIOC | 0x0),
	IOAT_IOCTL_READ_REG	= (IOATIOC | 0x1),
	IOAT_IOCTL_TEST		= (IOATIOC | 0x2)
} ioat_ioctl_enum_t;

typedef struct ioat_ioctl_reg_s {
	uint_t		size;
	uint_t		addr;
	uint64_t	data;
} ioat_ioctl_reg_t;
typedef ioat_ioctl_reg_t ioat_ioctl_wrreg_t;
typedef ioat_ioctl_reg_t ioat_ioctl_rdreg_t;

#ifdef _KERNEL
/* *** Driver Private Below *** */

/* IOAT_DMACAPABILITY flags */
#define	IOAT_DMACAP_PAGEBREAK	0x1
#define	IOAT_DMACAP_CRC		0x2
#define	IOAT_DMACAP_MARKERSKIP	0x4
#define	IOAT_DMACAP_XOR		0x8
#define	IOAT_DMACAP_DCA		0x10

/* IOAT_INTRCTL bits */
#define	IOAT_INTRCTL_MASTER_EN	0x1
#define	IOAT_INTRCTL_INTR_STAT	0x2

/* MMIO Registers */
#define	IOAT_CHANCNT		0x0	/* 8-bit */
#define	IOAT_XFERCAP		0x1	/* 8-bit */
#define	IOAT_GENCTRL		0x2	/* 8-bit */
#define	IOAT_INTRCTL		0x3	/* 8-bit */
#define	IOAT_ATTNSTATUS		0x4	/* 32-bit */
#define	IOAT_CBVER		0x8	/* 8-bit */
#define	IOAT_PERPORT_OFF	0xA	/* 16-bit */
#define	IOAT_INTRDELAY		0xC	/* 16-bit */
#define	IOAT_CSSTATUS		0xE	/* 16-bit */
#define	IOAT_DMACAPABILITY	0x10	/* 32-bit */

#define	IOAT_CHANNELREG_OFFSET	0x80

/* Channel Registers */
#define	IOAT_CHAN_CTL		0x0	/* 16-bit */
#define	IOAT_CHAN_COMP		0x2	/* 16-bit */
#define	IOAT_CHAN_CMPL_LO	0x18	/* 32-bit */
#define	IOAT_CHAN_CMPL_HI	0x1C	/* 32-bit */
#define	IOAT_CHAN_ERR		0x28	/* 32-bit */
#define	IOAT_CHAN_ERRMASK	0x2C	/* 32-bit */
#define	IOAT_CHAN_DCACTRL	0x30	/* 32-bit */

#define	IOAT_V1_CHAN_STS_LO	0x4	/* 32-bit */
#define	IOAT_V1_CHAN_STS_HI	0x8	/* 32-bit */
#define	IOAT_V1_CHAN_ADDR_LO	0x0C	/* 32-bit */
#define	IOAT_V1_CHAN_ADDR_HI	0x10	/* 32-bit */
#define	IOAT_V1_CHAN_CMD	0x14	/* 8-bit */

#define	IOAT_V2_CHAN_CMD	0x4	/* 8-bit */
#define	IOAT_V2_CHAN_CNT	0x6	/* 16-bit */
#define	IOAT_V2_CHAN_STS_LO	0x8	/* 32-bit */
#define	IOAT_V2_CHAN_STS_HI	0xC	/* 32-bit */
#define	IOAT_V2_CHAN_ADDR_LO	0x10	/* 32-bit */
#define	IOAT_V2_CHAN_ADDR_HI	0x14	/* 32-bit */

#define	IOAT_CHAN_STS_ADDR_MASK		0xFFFFFFFFFFFFFFC0
#define	IOAT_CHAN_STS_XFER_MASK		0x3F
#define	IOAT_CHAN_STS_FAIL_MASK		0x6
#define	IOAT_CMPL_INDEX(channel)	\
	(((*channel->ic_cmpl & IOAT_CHAN_STS_ADDR_MASK) - \
	ring->cr_phys_desc) >> 6)
#define	IOAT_CMPL_FAILED(channel)	\
	(*channel->ic_cmpl & IOAT_CHAN_STS_FAIL_MASK)


typedef struct ioat_chan_desc_s {
	uint32_t	dd_res0;
	uint32_t	dd_ctrl;
	uint64_t	dd_res1;
	uint64_t	dd_res2;
	uint64_t	dd_next_desc;
	uint64_t	dd_res4;
	uint64_t	dd_res5;
	uint64_t	dd_res6;
	uint64_t	dd_res7;
} ioat_chan_desc_t;

/* dca dd_ctrl bits */
#define	IOAT_DESC_CTRL_OP_CNTX	((uint32_t)0xFF << 24)
#define	IOAT_DESC_CTRL_CNTX_CHNG	0x1
typedef struct ioat_chan_dca_desc_s {
	uint32_t	dd_cntx;
	uint32_t	dd_ctrl;
	uint64_t	dd_res1;
	uint64_t	dd_res2;
	uint64_t	dd_next_desc;
	uint64_t	dd_res4;
	uint64_t	dd_res5;
	uint64_t	dd_res6;
	uint64_t	dd_res7;
} ioat_chan_dca_desc_t;

/* dma dd_ctrl bits */
#define	IOAT_DESC_CTRL_OP_DMA	(0x0 << 24)
#define	IOAT_DESC_DMACTRL_NULL	0x20
#define	IOAT_DESC_CTRL_FENCE	0x10
#define	IOAT_DESC_CTRL_CMPL	0x8
#define	IOAT_DESC_CTRL_NODSTSNP	0x4
#define	IOAT_DESC_CTRL_NOSRCSNP	0x2
#define	IOAT_DESC_CTRL_INTR	0x1
typedef struct ioat_chan_dma_desc_s {
	uint32_t	dd_size;
	uint32_t	dd_ctrl;
	uint64_t	dd_src_paddr;
	uint64_t	dd_dest_paddr;
	uint64_t	dd_next_desc;
	uint64_t	dd_next_src_paddr;	/* v2 only */
	uint64_t	dd_next_dest_paddr;	/* v2 only */
	uint64_t	dd_res6;
	uint64_t	dd_res7;
} ioat_chan_dma_desc_t;


typedef enum {
	IOAT_CBv1,
	IOAT_CBv2
} ioat_version_t;

/* ioat private data per command */
typedef struct ioat_cmd_private_s {
	uint64_t	ip_generation;
	uint64_t	ip_index;
	uint64_t	ip_start;
	dcopy_cmd_t	ip_next;
} ioat_cmd_private_t;

/* descriptor ring state */
typedef struct ioat_channel_ring_s {
	/* protects cr_cmpl_gen & cr_cmpl_last */
	kmutex_t		cr_cmpl_mutex;

	/* desc ring generation for the last completion we saw */
	uint64_t		cr_cmpl_gen;

	/* last descriptor index we saw complete */
	uint64_t		cr_cmpl_last;

	/* protects cr_desc_* */
	kmutex_t		cr_desc_mutex;

	/*
	 * last descriptor posted. used to update its next pointer when we
	 * add a new desc. Also used to tack the completion (See comment for
	 * cr_desc_gen_prev).
	 */
	uint64_t		cr_desc_prev;

	/* where to put the next descriptor */
	uint64_t		cr_desc_next;

	/* what the current desc ring generation is */
	uint64_t		cr_desc_gen;

	/*
	 * used during cmd_post to track the last desc posted. cr_desc_next
	 * and cr_desc_gen will be pointing to the next free desc after
	 * writing the descriptor to the ring. But we want to track the
	 * completion for the last descriptor posted.
	 */
	uint64_t		cr_desc_gen_prev;

	/* the last desc in the ring (for wrap) */
	uint64_t		cr_desc_last;

	/* pointer to the head of the ring */
	ioat_chan_desc_t	*cr_desc;

	/* physical address of the head of the ring */
	uint64_t		cr_phys_desc;

	/* back pointer to the channel state */
	struct ioat_channel_s	*cr_chan;

	/* for CB v2, number of desc posted (written to IOAT_V2_CHAN_CNT) */
	uint_t			cr_post_cnt;
} ioat_channel_ring_t;

/* track channel state so we can handle a failure */
typedef enum {
	IOAT_CHANNEL_OK = 0,
	IOAT_CHANNEL_IN_FAILURE = 1
} ic_channel_state_t;

typedef struct ioat_channel_s *ioat_channel_t;
struct ioat_channel_s {
	/* channel's ring state */
	ioat_channel_ring_t	*ic_ring;

	/* IOAT_CBv1 || IOAT_CBv2 */
	ioat_version_t		ic_ver;

	/*
	 * state to determine if it's OK to post the the channel and if all
	 * future polls should return failure.
	 */
	ic_channel_state_t	ic_channel_state;

	/* channel command cache (*_cmd_alloc, *_cmd_free, etc) */
	kmem_cache_t		*ic_cmd_cache;

	/* dcopy state for dcopy_device_channel_notify() call */
	dcopy_handle_t		ic_dcopy_handle;

	/* location in memory where completions are DMA'ed into */
	volatile uint64_t	*ic_cmpl;

	/* channel specific registers */
	uint8_t			*ic_regs;

	/* if this channel is using DCA */
	boolean_t		ic_dca_active;

	/* DCA ID the channel is currently pointing to */
	uint32_t		ic_dca_current;

	/* devices channel number */
	uint_t			ic_chan_num;

	/* number of descriptors in ring */
	uint_t			ic_chan_desc_cnt;

	/* descriptor ring alloc state */
	ddi_dma_handle_t	ic_desc_dma_handle;
	size_t			ic_desc_alloc_size;
	ddi_acc_handle_t	ic_desc_handle;
	ddi_dma_cookie_t	ic_desc_cookies;

	/* completion buffer alloc state */
	ddi_dma_handle_t	ic_cmpl_dma_handle;
	size_t			ic_cmpl_alloc_size;
	ddi_acc_handle_t	ic_cmpl_handle;
	ddi_dma_cookie_t	ic_cmpl_cookie;
	uint64_t		ic_phys_cmpl;

	/* if inuse, we need to re-init the channel during resume */
	boolean_t		ic_inuse;

	/* backpointer to driver state */
	struct ioat_state_s	*ic_state;
};

typedef struct ioat_rs_s *ioat_rs_hdl_t;

/* driver state */
typedef struct ioat_state_s {
	dev_info_t		*is_dip;
	int			is_instance;

	kmutex_t		is_mutex;

	/* register handle and pointer to registers */
	ddi_acc_handle_t	is_reg_handle;
	uint8_t			*is_genregs;

	/* IOAT_CBv1 || IOAT_CBv2 */
	ioat_version_t		is_ver;

	/* channel state */
	ioat_channel_t		is_channel;
	size_t			is_chansize;
	ioat_rs_hdl_t		is_channel_rs;

	ddi_iblock_cookie_t	is_iblock_cookie;

	/* device info */
	uint_t			is_chanoff;
	uint_t			is_num_channels;
	uint_t			is_maxxfer;
	uint_t			is_cbver;
	uint_t			is_intrdelay;
	uint_t			is_status;
	uint_t			is_capabilities;

	/* dcopy_device_register()/dcopy_device_unregister() state */
	dcopy_device_handle_t	is_device_handle;
	dcopy_device_info_t	is_deviceinfo;
} ioat_state_t;


int ioat_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *cred,
    int *rval);

void ioat_rs_init(ioat_state_t *state, uint_t min_val, uint_t max_val,
    ioat_rs_hdl_t *handle);
void ioat_rs_fini(ioat_rs_hdl_t *handle);
int ioat_rs_alloc(ioat_rs_hdl_t handle, uint_t *rs);
void ioat_rs_free(ioat_rs_hdl_t handle, uint_t rs);

int ioat_channel_init(ioat_state_t *state);
void ioat_channel_fini(ioat_state_t *state);
void ioat_channel_suspend(ioat_state_t *state);
int ioat_channel_resume(ioat_state_t *state);
void ioat_channel_quiesce(ioat_state_t *);

int ioat_channel_alloc(void *device_private, dcopy_handle_t handle, int flags,
    uint_t size, dcopy_query_channel_t *info, void *channel_private);
void ioat_channel_free(void *channel_private);
void ioat_channel_intr(ioat_channel_t channel);
int ioat_cmd_alloc(void *channel, int flags, dcopy_cmd_t *cmd);
void ioat_cmd_free(void *channel, dcopy_cmd_t *cmd);
int ioat_cmd_post(void *channel, dcopy_cmd_t cmd);
int ioat_cmd_poll(void *channel, dcopy_cmd_t cmd);
void ioat_unregister_complete(void *device_private, int status);


#endif /* _KERNEL */

#ifdef __cplusplus
}
#endif

#endif /* _SYS_IOAT_H */