Print this page
5045 use atomic_{inc,dec}_* instead of atomic_add_*
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/uts/i86pc/sys/rootnex.h
+++ new/usr/src/uts/i86pc/sys/rootnex.h
1 1 /*
2 2 * CDDL HEADER START
3 3 *
4 4 * The contents of this file are subject to the terms of the
5 5 * Common Development and Distribution License (the "License").
6 6 * You may not use this file except in compliance with the License.
7 7 *
8 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 9 * or http://www.opensolaris.org/os/licensing.
10 10 * See the License for the specific language governing permissions
11 11 * and limitations under the License.
12 12 *
13 13 * When distributing Covered Code, include this CDDL HEADER in each
14 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 15 * If applicable, add the following below this CDDL HEADER, with the
16 16 * fields enclosed by brackets "[]" replaced with your own identifying
17 17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 18 *
19 19 * CDDL HEADER END
20 20 */
21 21 /*
22 22 * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
23 23 */
24 24
25 25 #ifndef _SYS_ROOTNEX_H
26 26 #define _SYS_ROOTNEX_H
27 27
28 28 /*
29 29 * x86 root nexus implementation specific state
30 30 */
31 31
32 32 #include <sys/types.h>
33 33 #include <sys/conf.h>
34 34 #include <sys/modctl.h>
35 35 #include <sys/sunddi.h>
36 36 #include <sys/iommulib.h>
37 37 #include <sys/sdt.h>
38 38
39 39 #ifdef __cplusplus
40 40 extern "C" {
41 41 #endif
42 42
43 43
↓ open down ↓ |
43 lines elided |
↑ open up ↑ |
44 44 /* size of buffer used for ctlop reportdev */
45 45 #define REPORTDEV_BUFSIZE 1024
46 46
47 47 /* min and max interrupt vectors */
48 48 #define VEC_MIN 1
49 49 #define VEC_MAX 255
50 50
51 51 /* atomic increment/decrement to keep track of outstanding binds, etc */
52 52 #ifdef DEBUG
53 53 #define ROOTNEX_DPROF_INC(addr) atomic_inc_64(addr)
54 -#define ROOTNEX_DPROF_DEC(addr) atomic_add_64(addr, -1)
54 +#define ROOTNEX_DPROF_DEC(addr) atomic_dec_64(addr)
55 55 #define ROOTNEX_DPROBE1(name, type1, arg1) \
56 56 DTRACE_PROBE1(name, type1, arg1)
57 57 #define ROOTNEX_DPROBE2(name, type1, arg1, type2, arg2) \
58 58 DTRACE_PROBE2(name, type1, arg1, type2, arg2)
59 59 #define ROOTNEX_DPROBE3(name, type1, arg1, type2, arg2, type3, arg3) \
60 60 DTRACE_PROBE3(name, type1, arg1, type2, arg2, type3, arg3)
61 61 #define ROOTNEX_DPROBE4(name, type1, arg1, type2, arg2, type3, arg3, \
62 62 type4, arg4) \
63 63 DTRACE_PROBE4(name, type1, arg1, type2, arg2, type3, arg3, type4, arg4)
64 64 #else
65 65 #define ROOTNEX_DPROF_INC(addr)
66 66 #define ROOTNEX_DPROF_DEC(addr)
67 67 #define ROOTNEX_DPROBE1(name, type1, arg1)
68 68 #define ROOTNEX_DPROBE2(name, type1, arg1, type2, arg2)
69 69 #define ROOTNEX_DPROBE3(name, type1, arg1, type2, arg2, type3, arg3)
70 70 #define ROOTNEX_DPROBE4(name, type1, arg1, type2, arg2, type3, arg3, \
71 71 type4, arg4)
72 72 #endif
73 73
74 74 /* set in dmac_type to signify that this cookie uses the copy buffer */
75 75 #define ROOTNEX_USES_COPYBUF 0x80000000
76 76
77 77 /*
78 78 * integer or boolean property name and value. A few static rootnex properties
79 79 * are created during rootnex attach from an array of rootnex_intprop_t..
80 80 */
81 81 typedef struct rootnex_intprop_s {
82 82 char *prop_name;
83 83 int prop_value;
84 84 } rootnex_intprop_t;
85 85
86 86 /*
87 87 * sgl related information which is visible to rootnex_get_sgl(). Trying to
88 88 * isolate get_sgl() as much as possible so it can be easily replaced.
89 89 */
90 90 typedef struct rootnex_sglinfo_s {
91 91 /*
92 92 * Used to simplify calculations to get the maximum number
93 93 * of cookies.
94 94 */
95 95 boolean_t si_cancross;
96 96
97 97 /*
98 98 * These are passed into rootnex_get_sgl().
99 99 *
100 100 * si_min_addr - the minimum physical address
101 101 * si_max_addr - the maximum physical address
102 102 * si_max_cookie_size - the maximum size of a physically contiguous
103 103 * piece of memory that we can handle in a sgl.
104 104 * si_segmask - segment mask to determine if we cross a segment boundary
105 105 * si_flags - dma_attr_flags
106 106 * si_max_pages - max number of pages this sgl could occupy (which
107 107 * is also the maximum number of cookies we might see.
108 108 */
109 109 uint64_t si_min_addr;
110 110 uint64_t si_max_addr;
111 111 uint64_t si_max_cookie_size;
112 112 uint64_t si_segmask;
113 113 uint_t si_flags;
114 114 uint_t si_max_pages;
115 115
116 116 /*
117 117 * these are returned by rootnex_get_sgl()
118 118 *
119 119 * si_bounce_on_seg - if we need to use bounce buffer for pages above
120 120 * ddi_dma_seg
121 121 * si_copybuf_req - amount of copy buffer needed by the buffer.
122 122 * si_buf_offset - The initial offset into the first page of the buffer.
123 123 * It's set in get sgl and used in the bind slow path to help
124 124 * calculate the current page index & offset from the current offset
125 125 * which is relative to the start of the buffer.
126 126 * si_asp - address space of buffer passed in.
127 127 * si_sgl_size - The actual number of cookies in the sgl. This does
128 128 * not reflect and sharing that we might do on window boundaries.
129 129 */
130 130 boolean_t si_bounce_on_seg;
131 131 size_t si_copybuf_req;
132 132 off_t si_buf_offset;
133 133 struct as *si_asp;
134 134 uint_t si_sgl_size;
135 135 } rootnex_sglinfo_t;
136 136
137 137 /*
138 138 * When we have to use the copy buffer, we allocate one of these structures per
139 139 * buffer page to track which pages need the copy buffer, what the kernel
140 140 * virtual address is (which the device can't reach), and what the copy buffer
141 141 * virtual address is (where the device dma's to/from). For 32-bit kernels,
142 142 * since we can't use seg kpm, we also need to keep the page_t around and state
143 143 * if we've currently mapped in the page into KVA space for buffers which don't
144 144 * have kva already and when we have multiple windows because we used up all our
145 145 * copy buffer space.
146 146 */
147 147 typedef struct rootnex_pgmap_s {
148 148 boolean_t pm_uses_copybuf;
149 149 #if !defined(__amd64)
150 150 boolean_t pm_mapped;
151 151 page_t *pm_pp;
152 152 caddr_t pm_vaddr;
153 153 #endif
154 154 caddr_t pm_kaddr;
155 155 caddr_t pm_cbaddr;
156 156 } rootnex_pgmap_t;
157 157
158 158 /*
159 159 * We only need to trim a buffer when we have multiple windows. Each window has
160 160 * trim state. We might have trimmed the end of the previous window, leaving the
161 161 * first cookie of this window trimmed[tr_trim_first] (which basically means we
162 162 * won't start with a new cookie), or we might need to trim the end of the
163 163 * current window [tr_trim_last] (which basically means we won't end with a
164 164 * complete cookie). We keep the same state for the first & last cookie in a
165 165 * window (a window can have one or more cookies). However, when we trim the
166 166 * last cookie, we keep a pointer to the last cookie in the trim state since we
167 167 * only need this info when we trim. The pointer to the first cookie in the
168 168 * window is in the window state since we need to know what the first cookie in
169 169 * the window is in various places.
170 170 *
171 171 * If we do trim a cookie, we save away the physical address and size of the
172 172 * cookie so that we can over write the cookie when we switch windows (the
173 173 * space for a cookie which is in two windows is shared between the windows.
174 174 * We keep around the same information for the last page in a window.
175 175 *
176 176 * if we happened to trim on a page that uses the copy buffer, and that page
177 177 * is also in the middle of a window boundary because we have filled up the
178 178 * copy buffer, we need to remember the copy buffer address for both windows
179 179 * since the same page will have different copy buffer addresses in the two
180 180 * windows. We need to due the same for kaddr in the 32-bit kernel since we
181 181 * have a limited kva space which we map to.
182 182 */
183 183 typedef struct rootnex_trim_s {
184 184 boolean_t tr_trim_first;
185 185 boolean_t tr_trim_last;
186 186 ddi_dma_cookie_t *tr_last_cookie;
187 187 uint64_t tr_first_paddr;
188 188 uint64_t tr_last_paddr;
189 189 size_t tr_first_size;
190 190 size_t tr_last_size;
191 191
192 192 boolean_t tr_first_copybuf_win;
193 193 boolean_t tr_last_copybuf_win;
194 194 uint_t tr_first_pidx;
195 195 uint_t tr_last_pidx;
196 196 caddr_t tr_first_cbaddr;
197 197 caddr_t tr_last_cbaddr;
198 198 #if !defined(__amd64)
199 199 caddr_t tr_first_kaddr;
200 200 caddr_t tr_last_kaddr;
201 201 #endif
202 202 } rootnex_trim_t;
203 203
204 204 /*
205 205 * per window state. A bound DMA handle can have multiple windows. Each window
206 206 * will have the following state. We track if this window needs to sync,
207 207 * the offset into the buffer where the window starts, the size of the window.
208 208 * a pointer to the first cookie in the window, the number of cookies in the
209 209 * window, and the trim state for the window. For the 32-bit kernel, we keep
210 210 * track of if we need to remap the copy buffer when we switch to a this window
211 211 */
212 212 typedef struct rootnex_window_s {
213 213 boolean_t wd_dosync;
214 214 uint_t wd_cookie_cnt;
215 215 off_t wd_offset;
216 216 size_t wd_size;
217 217 ddi_dma_cookie_t *wd_first_cookie;
218 218 rootnex_trim_t wd_trim;
219 219 #if !defined(__amd64)
220 220 boolean_t wd_remap_copybuf;
221 221 #endif
222 222 } rootnex_window_t;
223 223
224 224 /* per dma handle private state */
225 225 typedef struct rootnex_dma_s {
226 226 /*
227 227 * sgl related state used to build and describe the sgl.
228 228 *
229 229 * dp_partial_required - used in the bind slow path to identify if we
230 230 * need to do a partial mapping or not.
231 231 * dp_trim_required - used in the bind slow path to identify if we
232 232 * need to trim when switching to a new window. This should only be
233 233 * set when partial is set.
234 234 * dp_granularity_power_2 - set in alloc handle and used in bind slow
235 235 * path to determine if we & or % to calculate the trim.
236 236 * dp_dma - copy of dma "object" passed in during bind
237 237 * dp_maxxfer - trimmed dma_attr_maxxfer so that it is a whole
238 238 * multiple of granularity
239 239 * dp_sglinfo - See rootnex_sglinfo_t above.
240 240 */
241 241 boolean_t dp_partial_required;
242 242 boolean_t dp_trim_required;
243 243 boolean_t dp_granularity_power_2;
244 244 uint64_t dp_maxxfer;
245 245
246 246 boolean_t dp_dvma_used;
247 247 ddi_dma_obj_t dp_dma;
248 248 ddi_dma_obj_t dp_dvma;
249 249 rootnex_sglinfo_t dp_sglinfo;
250 250
251 251 /*
252 252 * Copy buffer related state
253 253 *
254 254 * dp_copybuf_size - the actual size of the copy buffer that we are
255 255 * using. This can be smaller that dp_copybuf_req, i.e. bind size >
256 256 * max copy buffer size.
257 257 * dp_cbaddr - kernel address of copy buffer. Used to determine where
258 258 * where to copy to/from.
259 259 * dp_cbsize - the "real" size returned from the copy buffer alloc.
260 260 * Set in the copybuf alloc and used to free copybuf.
261 261 * dp_pgmap - page map used in sync to determine which pages in the
262 262 * buffer use the copy buffer and what addresses to use to copy to/
263 263 * from.
264 264 * dp_cb_remaping - status if this bind causes us to have to remap
265 265 * the copybuf when switching to new windows. This is only used in
266 266 * the 32-bit kernel since we use seg kpm in the 64-bit kernel for
267 267 * this case.
268 268 * dp_kva - kernel heap arena vmem space for mapping to buffers which
269 269 * we don't have a kernel VA to bcopy to/from. This is only used in
270 270 * the 32-bit kernel since we use seg kpm in the 64-bit kernel for
271 271 * this case.
272 272 */
273 273 size_t dp_copybuf_size;
274 274 caddr_t dp_cbaddr;
275 275 size_t dp_cbsize;
276 276 rootnex_pgmap_t *dp_pgmap;
277 277 #if !defined(__amd64)
278 278 boolean_t dp_cb_remaping;
279 279 caddr_t dp_kva;
280 280 #endif
281 281
282 282 /*
283 283 * window related state. The pointer to the window state array which may
284 284 * be a pointer into the pre allocated state, or we may have had to
285 285 * allocate the window array on the fly because it wouldn't fit. If
286 286 * we allocate it, we'll use dp_need_to_free_window and dp_window_size
287 287 * during cleanup. dp_current_win keeps track of the current window.
288 288 * dp_max_win is the maximum number of windows we could have.
289 289 */
290 290 uint_t dp_current_win;
291 291 rootnex_window_t *dp_window;
292 292 boolean_t dp_need_to_free_window;
293 293 uint_t dp_window_size;
294 294 uint_t dp_max_win;
295 295
296 296 /* dip of driver which "owns" handle. set to rdip in alloc_handle() */
297 297 dev_info_t *dp_dip;
298 298
299 299 /*
300 300 * dp_mutex and dp_inuse are only used to see if a driver is trying to
301 301 * bind to an already bound dma handle. dp_mutex only used for dp_inuse
302 302 */
303 303 kmutex_t dp_mutex;
304 304 boolean_t dp_inuse;
305 305
306 306 /*
307 307 * cookie related state. The pointer to the cookies (dp_cookies) may
308 308 * be a pointer into the pre allocated state, or we may have had to
309 309 * allocate the cookie array on the fly because it wouldn't fit. If
310 310 * we allocate it, we'll use dp_need_to_free_cookie and dp_cookie_size
311 311 * during cleanup. dp_current_cookie is only used in the obsoleted
312 312 * interfaces to determine when we've used up all the cookies in a
313 313 * window during nextseg()..
314 314 */
315 315 size_t dp_cookie_size;
316 316 ddi_dma_cookie_t *dp_cookies;
317 317 boolean_t dp_need_to_free_cookie;
318 318 uint_t dp_current_cookie; /* for obsoleted I/Fs */
319 319 ddi_dma_cookie_t *dp_saved_cookies;
320 320 boolean_t dp_need_to_switch_cookies;
321 321
322 322 void *dp_iommu_private;
323 323
324 324 /*
325 325 * pre allocated space for the bind state, allocated during alloc
326 326 * handle. For a lot of devices, this will save us from having to do
327 327 * kmem_alloc's during the bind most of the time. kmem_alloc's can be
328 328 * expensive on x86 when the cpu count goes up since xcalls are
329 329 * expensive on x86.
330 330 */
331 331 uchar_t *dp_prealloc_buffer;
332 332
333 333 /*
334 334 * sleep flags set on bind and unset on unbind
335 335 */
336 336 int dp_sleep_flags;
337 337 } rootnex_dma_t;
338 338
339 339 /*
340 340 * profile/performance counters. Most things will be dtrace probes, but there
341 341 * are a couple of things we want to keep track all the time. We track the
342 342 * total number of active handles and binds (i.e. an alloc without a free or
343 343 * a bind without an unbind) since rootnex attach. We also track the total
344 344 * number of binds which have failed since rootnex attach.
345 345 */
346 346 typedef enum {
347 347 ROOTNEX_CNT_ACTIVE_HDLS = 0,
348 348 ROOTNEX_CNT_ACTIVE_BINDS = 1,
349 349 ROOTNEX_CNT_ALLOC_FAIL = 2,
350 350 ROOTNEX_CNT_BIND_FAIL = 3,
351 351 ROOTNEX_CNT_SYNC_FAIL = 4,
352 352 ROOTNEX_CNT_GETWIN_FAIL = 5,
353 353
354 354 /* This one must be last */
355 355 ROOTNEX_CNT_LAST
356 356 } rootnex_cnt_t;
357 357
358 358 /*
359 359 * global driver state.
360 360 * r_dmahdl_cache - dma_handle kmem_cache
361 361 * r_dvma_call_list_id - ddi_set_callback() id
362 362 * r_peekpoke_mutex - serialize peeks and pokes.
363 363 * r_dip - rootnex dip
364 364 * r_reserved_msg_printed - ctlops reserve message threshold
365 365 * r_counters - profile/performance counters
366 366 */
367 367 typedef struct rootnex_state_s {
368 368 uint_t r_prealloc_cookies;
369 369 uint_t r_prealloc_size;
370 370 kmem_cache_t *r_dmahdl_cache;
371 371 uintptr_t r_dvma_call_list_id;
372 372 kmutex_t r_peekpoke_mutex;
373 373 dev_info_t *r_dip;
374 374 ddi_iblock_cookie_t r_err_ibc;
375 375 boolean_t r_reserved_msg_printed;
376 376 uint64_t r_counters[ROOTNEX_CNT_LAST];
377 377 iommulib_nexhandle_t r_iommulib_handle;
378 378 } rootnex_state_t;
379 379
380 380 #ifdef __cplusplus
381 381 }
382 382 #endif
383 383
384 384 #endif /* _SYS_ROOTNEX_H */
↓ open down ↓ |
320 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX