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