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