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