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