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
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
|
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License, Version 1.0 only
* (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) 1999-2000 by Sun Microsystems, Inc.
* All rights reserved.
*/
#ifndef _SYS_1394_ADAPTERS_HCI1394_Q_H
#define _SYS_1394_ADAPTERS_HCI1394_Q_H
#pragma ident "%Z%%M% %I% %E% SMI"
/*
* hci1394_q.h
* This code decouples some of the OpenHCI async descriptor logic/structures
* from the async processing. The goal was to combine as much of the
* duplicate code as possible for the different type of async transfers
* without going too overboard.
*
* There are two parts to the Q, the descriptor buffer and the data buffer.
* for the most part, data to be transmitted and data which is received go
* in the data buffers. The information of where to get the data and put
* the data reside in the descriptor buffers. There are exceptions to this.
*/
#ifdef __cplusplus
extern "C" {
#endif
#include <sys/ddi.h>
#include <sys/modctl.h>
#include <sys/sunddi.h>
#include <sys/types.h>
#include <sys/note.h>
#include <sys/1394/adapters/hci1394_def.h>
#include <sys/1394/adapters/hci1394_tlist.h>
#include <sys/1394/adapters/hci1394_buf.h>
#include <sys/1394/adapters/hci1394_descriptors.h>
/*
* Part of q_info passed in during q_init(). This tells us if this is an async
* transmit or async receive Q. This makes a big difference inside of q. For
* the transmit Q we will just setup an empty Q ready for TX calls into us. For
* receive Q's we have to make sure we get multiple data buffers and then setup
* the buffers so they are ready to receive data (by adding in the IM
* descriptors).
*/
typedef enum {
HCI1394_ARQ,
HCI1394_ATQ
} hci1394_q_mode_t;
/*
* Part of q_info passed in during q_init(). These are the callbacks for
* starting and waking up the async Q's. When the first descriptor is placed
* on the Q, the async DMA engine is started with an address of where to find
* the descriptor on the Q. That descriptor will be changed to point to the
* next descriptor when the next descriptor is added (i.e. a chained dma).
* Whenever an additional descriptor is added, wake is called.
*/
typedef void (*hci1394_q_start_t)(void *arg, uint32_t io_addr);
typedef void (*hci1394_q_wake_t)(void *arg);
/*
* Passed in during q_init(). This contains the size of the descriptor Q, the
* size of the data Q, what kind of Q it is (AT or AR), the callbacks for start
* and wake, and the argument to pass during start and wake.
*/
typedef struct hci1394_q_info_s {
uint_t qi_desc_size;
uint_t qi_data_size;
hci1394_q_mode_t qi_mode;
hci1394_q_start_t qi_start;
hci1394_q_wake_t qi_wake;
void *qi_callback_arg;
} hci1394_q_info_t;
/*
* Per command tracking information for the AT Q's. This is not used on the AR
* side. This structure has two parts to it, the public data and the private
* data. The public data is shared between async.c and q.c. The private data
* is for internal q.c access only. It is only put in this structure so that
* we do not have to dynamically alloc space for each transfer.
*/
typedef struct hci1394_q_cmd_s {
/* PUBLIC DATA STRUCTURES */
/*
* qc_arg is an input paramter to hci1394_q_at() (along with the data
* versions). It is an opaque address pointer which is used by async.c
* to determine the commands address after a call to
* hci1394_q_at_next().
*/
void *qc_arg;
/*
* qc_generation is an input parameter to hci1394_q_at() (along with the
* data versions). It is the generation count for which this command is
* valid. If qc_generation does not match the current bus generation,
* hci1394_q_at*() will return failure.
*/
uint_t qc_generation;
/*
* qc_timestamp is used when sending an atresp to set the time when the
* response is to have timed out. It is also use on at_next to tell
* when the AT command completed.
*/
uint_t qc_timestamp;
/*
* qc_status is an output of hci1394_q_at_next(). It contains the
* command status after completion.
*/
uint32_t qc_status;
/* PRIVATE DATA STRUCTURES */
/*
* This is the memory address of where the status of this command
* resides.
*/
uint32_t *qc_status_addr;
/*
* qc_descriptor_end and qc_descriptor_buf are used to track where the
* descriptor q pointers should be set to when this command has
* completed (i.e. free up the space used by this command)
*/
caddr_t qc_descriptor_end;
uint_t qc_descriptor_buf;
/*
* qc_data_end and qc_data_buf are used to track where the data q
* pointers should be set to when this command has completed (i.e. free
* up the space used by this command). Not all commands use the data
* q so qc_data_used give us state on if this command uses the data q.
*/
boolean_t qc_data_used;
caddr_t qc_data_end;
uint_t qc_data_buf;
/*
* This is the node for the queued list. Since AT requests finish in
* the order that they were submitted, we queue these up in a linked
* list so that it is easy to figure out which command has finished.
* Just look at the head of the list.
*/
hci1394_tlist_node_t qc_node;
} hci1394_q_cmd_t;
_NOTE(SCHEME_PROTECTS_DATA("Single thread modifies", \
hci1394_q_cmd_s::qc_status \
hci1394_q_cmd_s::qc_timestamp))
typedef struct hci1394_q_bufptr_s {
/*
* kernel virtual addresses. The q may be broken down into multiple
* cookies. The q is contiguous relative to the driver, but segmented
* relative to the 1394 HW DMA engines.
*
* qp_top is the top the q. qp_bottom is the bottom of the q. These
* never change after initial setup. qp_bottom is inclusive (i.e. for a
* q size of 16 bytes where top was = to 0, qp_bottom would be = to 15).
*
* qp_current and qp_free are pointers within top and bottom. qp_current
* refers to the next free space to write and free refers to the end of
* free space (i.e. used memory within q). qp_free is inclusive (see
* qp_bottom).
*/
caddr_t qp_top;
caddr_t qp_bottom;
caddr_t qp_current;
caddr_t qp_free;
/*
* qp_begin and qp_end are also kernel virtual addresses. They are the
* beginning and ending address of the current_buf (cookie) within the
* q. qp_offset is (qp_current - qp_begin). This is used to determine
* the 32 bit PCI address to put into the OpenHCI descriptor. We know
* the base PCI address from the cookie structure, we add offset to that
* to determine the correct PCI address.
*/
caddr_t qp_begin;
caddr_t qp_end;
uint32_t qp_offset;
/*
* As stated above, the q may be broken into multiple cookies.
* qp_current_buf is the cookie qp_current is in and qp_free_buf is the
* cookie qp_free is in. NOTE: The cookie's are numbered 0, 1, 2, ...,
* (i.e. if we have 4 cookies, qp_current_buf can be 0, 1, 2, or 3)
*/
uint_t qp_current_buf;
uint_t qp_free_buf;
/*
* qp_resv_size is only used for the AT Q's.
* How much space has been reserved. This value is set on the call to
* hci1394_q_reserve() and decremented each time a data is written. It
* is used to check for overrun conditions. This extra check is in there
* as an added sanity check due to the complexity of this code.
*/
uint_t qp_resv_size;
} hci1394_q_bufptr_t;
typedef struct hci1394_q_buf_s {
/* pointers to track used/free space/cookies in the buffer */
hci1394_q_bufptr_t qb_ptrs;
/*
* a backup of qb_ptrs. If we fail while setting up an AT Q, we need to
* cleanup by putting things back the way that they were.
*/
hci1394_q_bufptr_t qb_backup_ptrs;
/* copy of all of the cookie's structures for this buffer */
ddi_dma_cookie_t qb_cookie[OHCI_MAX_COOKIE];
/* Buffer handle used for calls into hci1394_buf_* routines */
hci1394_buf_handle_t qb_buf_handle;
/* Buffer info (i.e. cookie count, kaddr, ddi handles, etc.) */
hci1394_buf_info_t qb_buf;
} hci1394_q_buf_t;
_NOTE(SCHEME_PROTECTS_DATA("Single thread modifies", \
hci1394_q_buf_s::qb_ptrs.qp_begin \
hci1394_q_buf_s::qb_ptrs.qp_bottom \
hci1394_q_buf_s::qb_ptrs.qp_current \
hci1394_q_buf_s::qb_ptrs.qp_current_buf \
hci1394_q_buf_s::qb_ptrs.qp_end \
hci1394_q_buf_s::qb_ptrs.qp_offset \
hci1394_q_buf_s::qb_ptrs.qp_top))
typedef struct hci1394_q_s {
/*
* q_queued_list is only used in the AT descriptor Qs. AT commands
* complete in the order they were issued. We Q these commands up with
* each new command being added to the end of the list. When a command
* completes, we look at the top of this list to determine which command
* completed.
*/
hci1394_tlist_handle_t q_queued_list;
/*
* pointer to general driver information (dip, instance, etc) and to
* handle for access to openHCI routines.
*/
hci1394_drvinfo_t *q_drvinfo;
hci1394_ohci_handle_t q_ohci;
/*
* The OpenHCI DMA engines are basically just chained DMA engines. Each
* "link" in the chain is called a descriptor in OpenHCI. When you want
* to add a new descriptor, you init the descriptor, setup its "next"
* pointer to "NULL", update the previous descriptor to point to the
* new descriptor, and tell the HW you added a new descriptor by setting
* its wake bit. q_previous is a pointer to the previous descriptor.
* When adding a new descriptor, we just de-reference q_previous to
* update its "next" pointer.
*/
hci1394_desc_t *q_previous;
/*
* When updating the "next" pointer in the previous descriptor block
* (as described above in q_previous), one of the things you need to
* tell the HW is how many 16 byte blocks the next descriptor block
* uses. This is what q_block_cnt is used for. This is only used in the
* AT descriptor Q's. Since the IM's used in the AR Q's are the only
* descriptor types used in AR, the block count is always the same for
* an AR descriptor Q.
*/
uint_t q_block_cnt;
/*
* q_head is only used in the AR descriptor Qs. It contains the location
* of the first descriptor on the Q. This is used to look at the
* residual count in the AR data Q. The residual count tells us if we
* have received any new packets to process. When a descriptor's data
* buffer is empty (q_space_left = 0), we move q_head to the next
* descriptor in the descriptor buffer.
*/
caddr_t q_head;
/*
* q_space_left is only used in the AR descriptor Qs. Each AR
* descriptor has residual count embedded in the descriptor which says
* how much free space is left in the descriptors associated data
* buffer. q_space_left is how much SW thinks is left in the data
* buffer. When they do not match, we have a new packet(s) in the data
* buffer to process. Since the residual count is not updated by the
* HW until the entire packet has been written to memory, we don't have
* to worry about any partial packet RX problems.
*/
uint_t q_space_left;
/*
* status of the dma controller. This tells us if we should do a start
* or a wake. If the dma engine is not running, we should start it. If
* it is running, we should wake it. When the DMA engine is started, it
* expects to have a valid descriptor to process. Since we don't have
* anything to send in the beginning (AT), we have to wait until the
* first AT packet comes down before we can start the DMA engine.
*/
boolean_t q_dma_running;
/* The descriptor buffer for this Q */
hci1394_q_buf_t q_desc;
/* The data buffer for this Q */
hci1394_q_buf_t q_data;
/* copy of qinfo passed in during hci1394_q_init() */
hci1394_q_info_t q_info;
kmutex_t q_mutex;
} hci1394_q_t;
_NOTE(SCHEME_PROTECTS_DATA("Single thread modifies", \
hci1394_q_s::q_dma_running \
hci1394_q_s::q_head \
hci1394_q_s::q_previous \
hci1394_q_s::q_space_left))
/* handle passed back from init() and used for rest of functions */
typedef struct hci1394_q_s *hci1394_q_handle_t;
int hci1394_q_init(hci1394_drvinfo_t *drvinfo,
hci1394_ohci_handle_t ohci_handle, hci1394_q_info_t *qinfo,
hci1394_q_handle_t *q_handle);
void hci1394_q_fini(hci1394_q_handle_t *q_handle);
void hci1394_q_resume(hci1394_q_handle_t q_handle);
void hci1394_q_stop(hci1394_q_handle_t q_handle);
int hci1394_q_at(hci1394_q_handle_t q_handle, hci1394_q_cmd_t *cmd,
hci1394_basic_pkt_t *hdr, uint_t hdrsize, int *result);
int hci1394_q_at_with_data(hci1394_q_handle_t q_handle, hci1394_q_cmd_t *cmd,
hci1394_basic_pkt_t *hdr, uint_t hdrsize, uint8_t *data, uint_t datasize,
int *result);
int hci1394_q_at_with_mblk(hci1394_q_handle_t q_handle, hci1394_q_cmd_t *cmd,
hci1394_basic_pkt_t *hdr, uint_t hdrsize, h1394_mblk_t *mblk, int *result);
void hci1394_q_at_next(hci1394_q_handle_t q_handle, boolean_t flush_q,
hci1394_q_cmd_t **cmd);
void hci1394_q_ar_next(hci1394_q_handle_t q_handle, uint32_t **q_addr);
void hci1394_q_ar_free(hci1394_q_handle_t q_handle, uint_t size);
uint32_t hci1394_q_ar_get32(hci1394_q_handle_t q_handle, uint32_t *addr);
void hci1394_q_ar_rep_get8(hci1394_q_handle_t q_handle, uint8_t *dest,
uint8_t *q_addr, uint_t size);
void hci1394_q_ar_copy_to_mblk(hci1394_q_handle_t q_handle, uint8_t *addr,
h1394_mblk_t *mblk);
#ifdef __cplusplus
}
#endif
#endif /* _SYS_1394_ADAPTERS_HCI1394_Q_H */
|