sunddi.c revision f4da9be01648d6afa604495d9b9956dddeb92a8c
* nullbusmap: The/DDI default bus_map entry point for nexi * not conforming to the reg/range paradigm (i.e. scsi, etc.) * with no HAT/MMU layer to be programmed at this level. * If the call is to map by rnumber, return an error, * otherwise pass anything else up the tree to my parent. * ddi_rnumber_to_regspec: Not for use by leaf drivers. * Only for use by nexi using the reg/range paradigm. * Note that we allow the dip to be nil because we may be called * prior even to the instantiation of the devinfo tree itself - all * regular leaf and nexus drivers should always use a non-nil dip! * We treat peek in a somewhat cavalier fashion .. assuming that we'll * simply get a synchronous fault as soon as we touch a missing address. * Poke is rather more carefully handled because we might poke to a write * buffer, "succeed", then only find some time later that we got an * asynchronous fault that indicated that the address we were writing to * was not really backed by hardware. /* Note: size is assumed to be correct; it is not checked. */ * A NULL value_p is permitted by ddi_peek(9F); discard the result. * Keep ddi_peek() and ddi_poke() in case 3rd parties are calling this. * they shouldn't be, but the 9f manpage kind of pseudo exposes it. * We need to separate the old interfaces from the new ones and leave them * in here for a while. Previous versions of the OS defined the new interfaces * to the old interfaces. This way we can fix things up so that we can * eventually remove these interfaces. * e.g. A 3rd party module/driver using ddi_peek8 and built against S10 * or earlier will actually have a reference to ddi_peekc in the binary. * We need to separate the old interfaces from the new ones and leave them * in here for a while. Previous versions of the OS defined the new interfaces * to the old interfaces. This way we can fix things up so that we can * eventually remove these interfaces. * e.g. A 3rd party module/driver using ddi_poke8 and built against S10 * or earlier will actually have a reference to ddi_pokec in the binary. * ddi_peekpokeio() is used primarily by the mem drivers for moving * data to and from uio structures via peek and poke. Note that we * use "internal" routines ddi_peek and ddi_poke to make this go * slightly faster, avoiding the call overhead .. * This still assumes that we might have an * I/O bus out there that permits 16-bit * transfers (and that it would be upset by * 32-bit transfers from such locations). * These routines are used by drivers that do layered ioctls * On sparc, they're implemented in assembler to avoid spilling * register windows in the common (copyin) case .. * Conversions in nexus pagesize units. We don't duplicate the * Request bus_ctl parent to handle a bus_ctl request return ((*
fp)(d, r,
op, a, v));
(
uint_t)0,
/* addr_t dlim_addr_lo */ (
uint_t)-
1,
/* addr_t dlim_addr_hi */ (
uint_t)-
1,
/* uint_t dlim_cntr_max */ (
uint_t)
1,
/* uint_t dlim_burstsizes */ (
uint_t)
1,
/* uint_t dlim_minxfer */ 0
/* uint_t dlim_dmaspeed */ (
uint_t)0,
/* addr_t dlim_addr_lo */ (
uint_t)
0xffffff,
/* addr_t dlim_addr_hi */ (
uint_t)0,
/* uint_t dlim_cntr_max */ (
uint_t)
0x00000001,
/* uint_t dlim_burstsizes */ (
uint_t)0,
/* uint_t dlim_dmaspeed */ (
uint_t)
0x86<<
24+0,
/* uint_t dlim_version */ (
uint_t)
0xffff,
/* uint_t dlim_adreg_max */ (
uint_t)
0xffff,
/* uint_t dlim_ctreg_max */ (
uint_t)
512,
/* uint_t dlim_granular */ (
int)
1,
/* int dlim_sgllen */ (
uint_t)
0xffffffff /* uint_t dlim_reqsizes */ * Handle the case that the requester is both a leaf * and a nexus driver simultaneously by calling the * requester's bus_dma_map function directly instead * Handle the case that the requester is both a leaf * and a nexus driver simultaneously by calling the * requester's bus_dma_map function directly instead * If the buffer has no proc pointer, or the proc * struct has the kernel address space, or the buffer has * been marked B_REMAPPED (meaning that it is now * mapped into the kernel's address space), then * the address space is kas (kernel address space). * Handle the case that the requester is both a leaf * and a nexus driver simultaneously by calling the * requester's bus_dma_map function directly instead * Request bus_dma_ctl parent to fiddle with a dma request. * For all DMA control functions, call the DMA control * routine and return status. * Just plain assume that the parent is to be called. * If a nexus driver or a thread outside the framework * of a nexus driver or a leaf driver calls these functions, * it is up to them to deal with the fact that the parent's * bus_dma_ctl function will be the first one called. * This routine is Obsolete and should be removed from ALL architectures * in a future release of Solaris. * It is deliberately NOT ported to amd64; please fix the code that * depends on this routine to use ddi_dma_nextcookie(9F). * NOTE: even though we fixed the pointer through a 32-bit param issue (the fix * is a side effect to some other cleanup), we're still not going to support #
endif /* (__i386 && !__amd64) || __sparc */ * The SPARC versions of these routines are done in assembler to * the DMA nexus driver will set DMP_NOSYNC if the * platform does not require any sync operation. For * example if the memory is uncached or consistent * and without any I/O write buffers involved. * DMA attributes, alignment, burst sizes, and transfer minimums * Make sure that the initial value is sane * Given two DMA attribute structures, apply the attributes * of one to the other, following the rules of attributes * and the wishes of the caller. * The rules of DMA attribute structures are that you cannot * make things *less* restrictive as you apply one set * of attributes to another. * ddi_segmap: setup the default segment driver. Calls the drivers * XXmmap routine to validate the range to be mapped. * Return ENXIO of the range is not valid. Create * a seg_dev segment that contains all of the * necessary information and will reference the * default segment driver routines. It returns zero * on success or non-zero on failure. * ddi_map_fault: Resolve mappings at fault time. Used by segment * drivers. Allows each successive parent to resolve * address translations and add its mappings to the * mapping list supplied in the page structure. It * returns zero on success or non-zero on failure. * ddi_device_mapping_check: Called from ddi_segmap_setup. * Invokes platform specific DDI to determine whether attributes specified * in attr(9s) are valid for the region of memory that will be made * available for direct access to user process via the mmap(2) system call. * we use e_ddi_hold_devi_by_dev to search for the devi. We * release it immediately since it should already be held by * Allocate and initialize the common elements of data * Set up the mapping request and call to parent. * Region must be mappable, pick up flags from the framework. * These functions are the framework for the property functions, * i.e. they support software defined properties. All implementation * specific property handling (i.e.: self-identifying devices and * PROM defined properties are handled in the implementation specific * nopropop: Shouldn't be called, right? printf(
"ddi_prop_debug: debugging %s\n",
enable ?
"enabled" :
"disabled");
#
endif /* DDI_PROP_DEBUG */ * Search a property list for a match, if found return pointer * to matching prop struct, else return NULL. * find the property in child's devinfo: * Search order defined by this search function is first matching * property with input dev == DDI_DEV_T_ANY matching any dev or * dev == propp->prop_dev, name == propp->name, and the correct * data type as specified in the flags. If a DDI_DEV_T_NONE dev * value made it this far then it implies a DDI_DEV_T_ANY search. * Search for property within devnames structures * Valid dev_t value is needed to index into the * correct devnames entry, therefore a dev_t * value of DDI_DEV_T_ANY is not appropriate. /* Property found, return it */ static char prop_no_mem_msg[] =
"can't allocate memory for ddi property <%s>";
* ddi_prop_search_global: * Search the global property list within devnames * for the named property. Return the encoded value. /* Property NOT found, bail */ * Return the encoded data * ddi_prop_search_common: Lookup and return the encoded value * find the property in child's devinfo: * 1. driver defined properties * 2. system defined properties * 3. driver global properties * 4. boot defined properties * Software property found? * If explicit undefine, return now. * If we only want to know if it exists, return now * If length only request or prop length == 0, * service request and return now. * if prop_op is PROP_LEN_AND_VAL_ALLOC * that means prop_len is 0, so set valuep * If LEN_AND_VAL_ALLOC and the request can sleep, * drop the mutex, allocate the buffer, and go * through the loop again. If we already allocated * the buffer, and the size of the property changed, * Allocate buffer, if required. Either way, i = *
lengthp;
/* Get callers length */ /* Set callers buf ptr */ * Prop not found, call parent bus_ops to deal with possible * h/w layer (possible PROM defined props, etc.) and to * possibly ascend the hierarchy, if allowed by flags. * One last call for the root driver PROM props? * We may have been called to check for properties * within a single devinfo node that has no parent - * Instead of recursing, we do iterative calls up the tree. * As a bit of optimization, skip the bus_op level if the * node is a s/w node and if the parent's bus_prop_op function * is `ddi_bus_prop_op', because we know that in this case, * this function does nothing. * 4225415: If the parent isn't attached, or the child * hasn't been named by the parent yet, use the default * ddi_bus_prop_op as a proxy for the parent. This * include 'prom' and inherited properties, even when * there are no drivers attached to the child or parent. * ddi_prop_op: The basic property operator for drivers. * In ddi_prop_op, the type of valuep is interpreted based on prop_op: * PROP_LEN_AND_VAL_BUF Pointer to callers buffer * PROP_LEN_AND_VAL_ALLOC Address of callers pointer (will be set to * address of allocated buffer, if successful) * If this was originally an LDI prop lookup then we bail here. * The reason is that the LDI property lookup interfaces first call * a drivers prop_op() entry point to allow it to override * properties. But if we've made it here, then the driver hasn't * overriden any properties. We don't want to continue with the * property search here because we don't have any type inforamtion. * When we return failure, the LDI interfaces will then proceed to * call the typed property interfaces to look up the property. * check for pre-typed property consumer asking for typed property: * see e_ddi_getprop_int64. * ddi_prop_op_nblocks: The basic property operator for drivers that maintain * size in number of DEV_BSIZE blocks. Provides a dynamic property * implementation for size oriented properties based on nblocks64 values passed * in by the driver. Fallback to ddi_prop_op if the nblocks64 is too large. * This interface should not be used with a nblocks64 that represents the * driver's idea of how to represent unknown, if nblocks is unknown use * There is no point in supporting nblocks64 values that don't have * an accurate uint64_t byte count representation. * ddi_prop_op_size: The basic property operator for drivers that maintain size * in bytes. Provides a of dynamic property implementation for size oriented * properties based on size64 values passed in by the driver. Fallback to * ddi_prop_op if the size64 is too large. This interface should not be used * with a size64 that represents the driver's idea of how to represent unknown, * if size is unknown use ddi_prop_op. * NOTE: the legacy "nblocks"/"size" properties are treated as 32-bit unsigned * integers. While the most likely interface to request them ([bc]devi_size) * is declared int (signed) there is no enforcement of this, which means we * can't enforce limitations here without risking regression. /* compute DEV_BSIZE nblocks value */ /* get callers length, establish length of our dynamic properties */ /* fallback to ddi_prop_op */ /* service request for the length of the property */ /* the length of the property and the request must match */ /* transfer the value into the buffer */ * Variable length props... * ddi_getlongprop: Get variable length property len+val into a buffer * allocated by property provider via kmem_alloc. Requester * is responsible for freeing returned property via kmem_free. * dev_t: Input: dev_t of property. * dip: Input: dev_info_t pointer of child. * flags: Input: Possible flag modifiers are: * DDI_PROP_DONTPASS: Don't pass to parent if prop not found. * DDI_PROP_CANSLEEP: Memory allocation may sleep. * name: Input: name of property. * valuep: Output: Addr of callers buffer pointer. * lengthp:Output: *lengthp will contain prop length on exit. * DDI_PROP_SUCCESS: Prop found and returned. * DDI_PROP_NOT_FOUND: Prop not found * DDI_PROP_UNDEFINED: Prop explicitly undefined. * DDI_PROP_NO_MEMORY: Prop found, but unable to alloc mem. * ddi_getlongprop_buf: Get long prop into pre-allocated callers * buffer. (no memory allocation by provider). * dev_t: Input: dev_t of property. * dip: Input: dev_info_t pointer of child. * flags: Input: DDI_PROP_DONTPASS or NULL * name: Input: name of property * valuep: Input: ptr to callers buffer. * lengthp:I/O: ptr to length of callers buffer on entry, * actual length of property on exit. * DDI_PROP_SUCCESS Prop found and returned * DDI_PROP_NOT_FOUND Prop not found * DDI_PROP_UNDEFINED Prop explicitly undefined. * DDI_PROP_BUF_TOO_SMALL Prop found, callers buf too small, * no value returned, but actual prop * length returned in *lengthp * Call is value only... returns found boolean or int sized prop value or * defvalue if prop not found or is wrong length or is explicitly undefined. * Only flag is DDI_PROP_DONTPASS... * By convention, this interface returns boolean (0) sized properties * This never returns an error, if property not found or specifically * undefined, the input `defvalue' is returned. * Get prop length interface: flags are 0 or DDI_PROP_DONTPASS * if returns DDI_PROP_SUCCESS, length returned in *lengthp. * Allocate a struct prop_driver_data, along with 'size' bytes * for decoded property data. This structure is freed by * calling ddi_prop_free(9F). * Allocate a structure with enough memory to store the decoded data. * Return a pointer to the location to put the decoded data. * Allocated the memory needed to store the encoded data in the property * If size is zero, then set data to NULL and size to 0. This * Free the space allocated by the lookup routines. Each lookup routine * returns a pointer to the decoded data to the driver. The driver then * passes this pointer back to us. This data actually lives in a struct * prop_driver_data. We use negative indexing to find the beginning of * the structure and then free the entire structure using the size and * the free routine stored in the structure. * Call the free routine to free it * Free the data associated with an array of ints, * allocated with ddi_prop_decode_alloc(). * Free a single string property or a single string contained within * the argv style return value of an array of strings. * Free an array of strings. * Free the data associated with an array of bytes. * Reset the current location pointer in the property handle to the * Restore the current location pointer in the property handle to the * Save the location that the current location pointer is pointing to.. * Decode a single integer property * If there is nothing to decode return an error * Decode the property as a single integer and return it * in data if we were able to decode it. * Decode a single 64 bit integer property * If there is nothing to decode return an error * Decode the property as a single integer and return it * in data if we were able to decode it. * Decode an array of integers property * Figure out how many array elements there are by going through the * data without decoding it first and counting. * If there are no elements return an error * If we cannot skip through the data, we cannot decode it * Reset the data pointer to the beginning of the encoded data * Allocated memory to store the decoded value in. * Decode each element and place it in the space we just allocated for (n = 0; n <
cnt; n++,
tmp++) {
* Free the space we just allocated * Decode a 64 bit integer array property * Count the number of array elements by going * through the data without decoding it. * If there are no elements return an error * If we cannot skip through the data, we cannot decode it * Reset the data pointer to the beginning of the encoded data * Allocate memory to store the decoded value. * Decode each element and place it in the space allocated for (n = 0; n <
cnt; n++,
tmp++) {
* Free the space we just allocated * Encode an array of integers property (Can be one element) * If there is no data, we cannot do anything * Get the size of an encoded int. * Allocate space in the handle to store the encoded int. * Encode the array of ints. * Encode a 64 bit integer array property * If there is no data, we cannot do anything * Get the size of an encoded 64 bit int. * Allocate space in the handle to store the encoded int. * Encode the array of ints. * Decode a single string property * If there is nothing to decode return an error * Get the decoded size of the encoded string. * Allocated memory to store the decoded value in. * Decode the str and place it in the space we just allocated * Free the space we just allocated * Decode an array of strings. * Figure out how many array elements there are by going through the * data without decoding it first and counting. * If there are no elements return an error * If we cannot skip through the data, we cannot decode it * Reset the data pointer to the beginning of the encoded data * Figure out how much memory we need for the sum total for (n = 0; n <
cnt; n++) {
* Get the decoded size of the current encoded string. * Allocate memory in which to store the decoded strings. * Set up pointers for each string by figuring out yet * again how long each string is. * Get the decoded size of the current encoded string. * String array is terminated by a NULL * Finally, we can decode each string * Free the space we just allocated * If there is no data, we cannot do anything * Get the size of the encoded string. * Allocate space in the handle to store the encoded string. * Encode an array of strings. * If there is no data, we cannot do anything * Get the total size required to encode all the strings. * Allocate space in the handle to store the encoded strings. * Encode the array of strings. * Decode an array of bytes. * If there are no elements return an error * Get the size of the encoded array of bytes. * Allocated memory to store the decoded value in. * Decode each element and place it in the space we just allocated * Free the space we just allocated * Encode an array of bytes. * If there are no elements, then this is a boolean property, * so just create a property handle with no data and return. * Get the size of the encoded array of bytes. * Allocate space in the handle to store the encoded bytes. * Encode the array of bytes. * OBP 1275 integer, string and byte operators. * DDI_PROP_RESULT_ERROR: cannot decode the data * DDI_PROP_RESULT_EOF: end of data * DDI_PROP_OK: data was decoded * DDI_PROP_RESULT_ERROR: cannot encode the data * DDI_PROP_RESULT_EOF: end of data * DDI_PROP_OK: data was encoded * DDI_PROP_RESULT_ERROR: cannot skip the data * DDI_PROP_RESULT_EOF: end of data * DDI_PROP_OK: data was skipped * DDI_PROP_CMD_GET_ESIZE: * DDI_PROP_RESULT_ERROR: cannot get encoded size * DDI_PROP_RESULT_EOF: end of data * DDI_PROP_CMD_GET_DSIZE: * DDI_PROP_RESULT_ERROR: cannot get decoded size * DDI_PROP_RESULT_EOF: end of data * OBP 1275 integer operator * OBP properties are a byte stream of data, so integers may not be * properly aligned. Therefore we need to copy them one byte at a time. * Check that there is encoded data * Copy the integer, using the implementation-specific * copy function if the property is coming from the PROM. * Move the current location to the start of the next * Check that there is room to encoded the data * Encode the integer into the byte stream one byte at a * Move the current location to the start of the next bit of * space where we can store encoded data. * Check that there is encoded data * Move the current location to the start of the next bit of * Return the size of an encoded integer on OBP * Return the size of a decoded integer on the system. panic(
"ddi_prop_1275_int: %x impossible",
cmd);
* 64 bit integer operator. * This is an extension, defined by Sun, to the 1275 integer * 64 bit integer properties. * Check that there is encoded data * Copy the integer, using the implementation-specific * copy function if the property is coming from the PROM. * Move the current location to the start of the next * Check that there is room to encoded the data * Encode the integer into the byte stream one byte at a * Move the current location to the start of the next bit of * space where we can store encoded data. * Check that there is encoded data * Move the current location to the start of * the next bit of undecoded data. * Return the size of an encoded integer on OBP * Return the size of a decoded integer on the system. panic(
"ddi_prop_int64_op: %x impossible",
cmd);
* OBP 1275 string operator. * OBP strings are NULL terminated. * Check that there is encoded data * Match DDI_PROP_CMD_GET_DSIZE logic for when to stop and * how to NULL terminate result. if (*p++ == 0) {
/* NULL from OBP */ * If OBP did not NULL terminate string, which happens * (at least) for 'true'/'false' boolean values, account for * the space and store null termination on decode. * Check that there is room to encoded the data * Copy the NULL terminated string * Move the current location to the start of the next bit of * space where we can store encoded data. * Check that there is encoded data * Return the string length plus one for the NULL * We know the size of the property, we need to * ensure that the string is properly formatted, * since we may be looking up random OBP data. if (*p++ == 0) {
/* NULL from OBP */ * Accommodate the fact that OBP does not always NULL * Return the size of the encoded string on OBP. * Return the string length plus one for the NULL. * We know the size of the property, we need to * ensure that the string is properly formatted, * since we may be looking up random OBP data. for (n = 0; p <
end; n++) {
if (*p++ == 0) {
/* NULL from OBP */ * If OBP did not NULL terminate string, which happens for * 'true'/'false' boolean values, account for the space * to store null termination here. panic(
"ddi_prop_1275_string: %x impossible",
cmd);
* Caller must specify the number of bytes to get. OBP encodes bytes * as a byte so there is a 1-to-1 translation. * Check that there is encoded data * Move the current location * Check that there is room to encode the data * Move the current location to the start of the next bit of * space where we can store encoded data. * Check that there is encoded data * Move the current location * The size in bytes of the encoded size is the * same as the decoded size provided by the caller. * Just return the number of bytes specified by the caller. panic(
"ddi_prop_1275_bytes: %x impossible",
cmd);
* Used for properties that come from the OBP, hardware configuration files, * or that are created by calls to ddi_prop_update(9F). * Interface to create/modify a managed property on child's behalf... * DDI_PROP_CANSLEEP: Allow memory allocation to sleep. * DDI_PROP_SYSTEM_DEF: Manipulate system list rather than driver list. * Use same dev_t when modifying or undefining a property. * Search for properties with DDI_DEV_T_ANY to match first named * Properties are stored LIFO and subsequently will match the first * ddi_prop_add: Add a software defined property * define to get a new ddi_prop_t. * km_flags are KM_SLEEP or KM_NOSLEEP. * If dev_t is DDI_DEV_T_ANY or name's length is zero return error. * If dev is major number 0, then we need to do a ddi_name_to_major * to get the real major number for the device. This needs to be * done because some drivers need to call ddi_prop_create in their * attach routines but they don't have a dev. By creating the dev * ourself if the major number is 0, drivers will not have to know what * their major number. They can just create a dev with major number * 0 and pass it in. For device 0, we will be doing a little extra * work by recreating the same dev that we already have, but its the * This fixes bug #1098060. * Allocate space for property name and copy it in... * Set length and value ONLY if not an explicit property undefine: * NOTE: value and length are zero for explicit undefines. * Link property into beginning of list. (Properties are LIFO order.) * ddi_prop_change: Modify a software managed property value * Set new length and value if found. * returns DDI_PROP_INVAL_ARG if dev is DDI_DEV_T_ANY or * input name is the NULL string. * returns DDI_PROP_NO_MEMORY if unable to allocate memory * Note: an undef can be modified to be a define, * (you can't go the other way.) * Preallocate buffer, even if we don't need it... * If the dev_t value contains DDI_MAJOR_T_UNKNOWN for the major * number, a real dev_t value should be created based upon the dip's * binding driver. See ddi_prop_add... * Check to see if the property exists. If so we modify it. * Else we create it by calling ddi_prop_add(). * Need to reallocate buffer? If so, do it * carefully (reuse same space if new prop * is same size and non-NULL sized). * Common update routine used to update and encode a property. Creates * a property handle, calls the property encode routine, figures out if * the property already exists and updates if it does. Otherwise it * creates if it does not exist. * If dev_t is DDI_DEV_T_ANY or name's length is zero, * For compatibility with the old interfaces. The old interfaces * didn't sleep by default and slept when the flag was set. These * interfaces to the opposite. So the old interfaces now set the * DDI_PROP_DONTSLEEP flag by default which tells us not to sleep. * Blocked data or unblocked data allocation * for ph.ph_data in ddi_prop_encode_alloc() * Encode the data and store it in the property handle by * calling the prop_encode routine. * The old interfaces use a stacking approach to creating * properties. If we are being called from the old interfaces, * the DDI_PROP_STACK_CREATE flag will be set, so we just do a * create without checking. * Free the encoded data allocated in the prop_encode routine. * ddi_prop_create: Define a managed property: "use ddi_prop_update (prop = %s, node = %s%d)",
#
endif /* DDI_PROP_DEBUG */ * If dev_t is DDI_DEV_T_ANY or name's length is zero, * If dev_t is DDI_DEV_T_ANY or name's length is zero, * Common lookup routine used to lookup and decode a property. * Creates a property handle, searches for the raw encoded data, * fills in the handle, and calls the property decode functions * This routine is not static because ddi_bus_prop_op() which lives in * ddi_impl.c calls it. No driver should be calling this routine. * For unbound dlpi style-2 devices, index into * the devnames' array and search the global * If the encoded data came from a OBP or software * Lookup and return an array of composite properties. The driver must * provide the decode routine. * Return 1 if a property exists (no type checking done). * Return 0 if it does not exist. * Update an array of composite properties. The driver must * provide the encode routine. * Get a single integer or boolean property and return it. * If the property does not exists, or cannot be decoded, * then return the defvalue passed in. * This routine always succeeds. " 0x%x (prop = %s, node = %s%d)",
flags,
* Get a single 64 bit integer or boolean property and return it. * If the property does not exists, or cannot be decoded, * then return the defvalue passed in. * This routine always succeeds. " 0x%x (prop = %s, node = %s%d)",
flags,
* Get an array of integer property "invalid flag 0x%x (prop = %s, node = %s%d)",
* Get an array of 64 bit integer properties "invalid flag 0x%x (prop = %s, node = %s%d)",
* Update a single integer property. If the property exists on the drivers * property list it updates, else it creates it. * Update a single 64 bit integer property. * Update the driver property list if it exists, else create it. * Update an array of integer property. If the property exists on the drivers * property list it updates, else it creates it. * Update an array of 64 bit integer properties. * Update the driver property list if it exists, else create it. * Get a single string property. "(prop = %s, node = %s%d); invalid bits ignored",
* Get an array of strings property. "invalid flag 0x%x (prop = %s, node = %s%d)",
* Update a single string property. * Update an array of strings property. * Get an array of bytes property. " invalid flag 0x%x (prop = %s, node = %s%d)",
* Update an array of bytes property. * ddi_prop_remove_common: Undefine a managed property: * Input dev_t must match dev_t when defined. * Returns DDI_PROP_NOT_FOUND, possibly. * DDI_PROP_INVAL_ARG is also possible if dev is * DDI_DEV_T_ANY or incoming name is the NULL string. * Unlink this propp allowing for it to * Free memory and return... * e_ddi_prop_list_delete: remove a list of properties * Note that the caller needs to provide the required protection * (eg. devi_lock if these properties are still attached to a devi) * ddi_prop_remove_all_common: * Used before unloading a driver to remove * all properties. (undefines all dev_t's props.) * Also removes `explicitly undefined' props. * ddi_prop_remove_all: Remove all driver prop definitions. * e_ddi_prop_remove_all: Remove all system prop definitions. * ddi_prop_undefine: Explicitly undefine a property. Property * searches which match this property return * the error code DDI_PROP_UNDEFINED. * Use ddi_prop_remove to negate effect of * See above for error returns. * Code to search hardware layer (PROM), if it exists, on behalf of child. * if input dip != child_dip, then call is on behalf of child * to search PROM, do it via ddi_prop_search_common() and ascend only * if input dip == ch_dip (child_dip), call is on behalf of root driver, * to search for PROM defined props only. * Note that the PROM search is done only if the requested dev * is either DDI_DEV_T_ANY or DDI_DEV_T_NONE. PROM properties * have no associated dev, thus are automatically associated with * Modifying flag DDI_PROP_NOTPROM inhibits the search in the h/w layer. * Returns DDI_PROP_FOUND_1275 if found to indicate to framework * that the property resides in the prom. * If requested dev is DDI_DEV_T_NONE or DDI_DEV_T_ANY, then * look in caller's PROM if it's a self identifying device... * Note that this is very similar to ddi_prop_op, but we * search the PROM instead of the s/w defined properties, * and we are called on by the parent driver to do this for * If exists only request, we're done * If length only request or prop length == 0, get out * Allocate buffer if required... (either way `buffer' * Call the PROM function to do the copy. *
lengthp =
len;
/* return the actual length to the caller */ * The ddi_bus_prop_op default bus nexus prop op function. * Code to search hardware layer (PROM), if it exists, * on behalf of child, then, if appropriate, ascend and check * my own software defined properties... * Check the 'options' node as a last resort * As a last resort, when we've reached * the top and still haven't found the * property, see if the desired property * is attached to the options node. * The options dip is attached right after boot. * Force the "don't pass" flag to *just* see * what the options node has to offer. * Otherwise, continue search with parent's s/w defined properties... * NOTE: Using `dip' in following call increments the level. * External property functions used by other parts of the kernel... * e_ddi_getlongprop: See comments for ddi_get_longprop. * e_ddi_getlongprop_buf: See comments for ddi_getlongprop_buf. * e_ddi_getprop: See comments for ddi_getprop. * This is a typed interfaces, but predates typed properties. With the * introduction of typed properties the framework tries to ensure * consistent use of typed interfaces. This is why TYPE_INT64 is not * part of TYPE_ANY. E_ddi_getprop_int64 is a special case where a * typed interface invokes legacy (non-typed) interfaces: * cdev_prop_op(), prop_op(9E), ddi_prop_op(9F)). In this case the * fact that TYPE_INT64 is not part of TYPE_ANY matters. To support * this type of lookup as a single operation we invoke the legacy * non-typed interfaces with the special CONSUMER_TYPED bit set. The * framework ddi_prop_op(9F) implementation is expected to check for * CONSUMER_TYPED and, if set, expand type bits beyond TYPE_ANY * (currently TYPE_INT64). * e_ddi_getproplen: See comments for ddi_getproplen. * Routines to get at elements of the dev_info structure * ddi_binding_name: Return the driver binding name of the devinfo node * This is the name the OS used to bind the node to a driver. * ddi_driver_major: Return the major number of the driver that * the supplied devinfo is bound to (-1 if none) * ddi_driver_name: Return the normalized driver name. this is the * i_ddi_set_binding_name: Set binding name. * Set the binding name to the given name. * This routine is for use by the ddi implementation, not by drivers. * ddi_get_name: A synonym of ddi_binding_name() ... returns a name * the implementation has used to bind the node to a driver. * ddi_node_name: Return the name property of the devinfo node * This may differ from ddi_binding_name if the node name * does not define a binding to a driver (i.e. generic names). * ddi_get_nodeid: Get nodeid stored in dev_info structure. * Get/set device driver private data in devinfo. * ddi_get_parent, ddi_get_child, ddi_get_next_sibling * ddi_root_node: Return root node of devinfo tree * Miscellaneous functions: * Implementation specific hooks * If this devinfo node has cb_ops, it's implicitly accessible from * userland, so we print its full name together with the instance * number 'abbreviation' that the driver may use internally. * ddi_ctlops() is described in the assembler not to buy a new register * window when it's called and can reduce cost in climbing the device tree * without using the tail call optimization. * callbacks are handled using a L1/L2 cache. The L1 cache * comes out of kmem_cache_alloc and can expand/shrink dynamically. If * we can't get callbacks from the L1 cache [because pageout is doing * I/O at the time freemem is 0], we allocate callbacks out of the * L2 cache. The L2 cache is static and depends on the memory size. * [We might also count the number of devices at probe time and * allocate one structure per device and adjust for deferred attach] * A driver should support its own getinfo(9E) entry point. This function * is provided as a convenience for ON drivers that don't expect their * getinfo(9E) entry point to be called. A driver that uses this must not * call ddi_create_minor_node. * A driver should support its own getinfo(9E) entry point. This function * is provided as a convenience for ON drivers that where the minor number * is the instance. Drivers that do not have 1:1 mapping must implement * their own getinfo(9E) function. * This function returns B_TRUE if the caller can reasonably expect that a call * to cv_wait_sig(9F), cv_timedwait_sig(9F), or qwait_sig(9F) could be awakened * by user-level signal. If it returns B_FALSE, then the caller should use * other means to make certain that the wait will not hang "forever." * It does not check the signal mask, nor for reception of any particular * Currently, a thread can receive a signal if it's not a kernel thread and it * is not in the middle of exit(2) tear-down. Threads that are in that * tear-down effectively convert cv_wait_sig to cv_wait, cv_timedwait_sig to * cv_timedwait, and qwait_sig to qwait. * Swap bytes in 16-bit [half-]words * Part of the obsolete SunCluster DDI Hooks. * Keep for binary compatibility /* determine interrupt context */ "interrupt level by driver %s",
* allow for NULL minor names "for driver %s (%s). Run devfsadm -i %s",
"for driver %s. Run devfsadm -i %s",
* failing to remove a minor node is not of interest * therefore we do not generate an error message * only log ddi_remove_minor_node() calls outside the scope * allow for NULL minor names * Derive the device class of the node. * Device class names aren't defined yet. Until this is done we use * devfs event subclass names as device class names. * Check compliance with PSARC 2003/375: * The name must contain only characters a-z, A-Z, 0-9 or _ and it must not * exceed IFNAMSIZ (16) characters in length. * ddi_create_minor_common: Create a ddi_minor_data structure and * attach it to the given devinfo node. * Log a message if the minor number the driver is creating * is not expressible on the on-disk filesystem (currently * this is limited to 18 bits both by UFS). The device can * be opened via devfs, but not by device special files created "%s%d:%s minor 0x%x too big for 32-bit applications",
/* dip must be bound and attached */ * Default node_type to DDI_PSEUDO and issue notice in debug mode " minor node %s; default to DDI_PSEUDO",
* If the driver is a network driver, ensure that the name falls within * the interface naming constraints specified by PSARC/2003/375. /* Mark driver as a network driver */ * Take care of minor number information for the node. * only log ddi_create_minor_node() calls which occur * outside the scope of attach(9e)/detach(9e) reconfigurations * Check if any dacf rules match the creation of this minor node * Internal (non-ddi) routine for drivers to export names known * to the kernel (especially ddi_pathname_to_dev_t and friends) * but not exported externally to /dev * Release device privilege, if any. * Release dacf client data associated with this minor * OK, we found it, so get out now -- if we drive on, * we will strcmp against garbage. See 1139209. * Find first bit set in a mask (returned counting from 1 up) * Find last bit set. Take mask and clear * all but the most significant bit, and * then let ffs do the rest of the work. * Algorithm courtesy of Steve Chessin. * The next five routines comprise generic storage management utilities * for driver soft state structures (in "the old days," this was done * with a statically sized array - big systems and dynamic loading * and unloading make heap allocation more attractive) * Allocate a set of pointers to 'n_items' objects of size 'size' * bytes. Each pointer is initialized to nil. * The 'size' and 'n_items' values are stashed in the opaque * handle returned to the caller. * This implementation interprets 'set of pointers' to mean 'array * of pointers' but note that nothing in the interface definition * precludes an implementation that uses, for example, a linked list. * However there should be a small efficiency gain from using an array * NOTE As an optimization, we make our growable array allocations in * powers of two (bytes), since that's how much kmem_alloc (currently) * gives us anyway. It should save us some free/realloc's .. * As a further optimization, we make the growable array start out * with MIN_N_ITEMS in it. * Allocate a state structure of size 'size' to be associated * In this implementation, the array is extended to * allow the requested offset, if needed. * refuse to tread on an existing element * Allocate a new element to plug in * Check if the array is big enough, if not, grow it. * Allocate a new array of the right length, copy * all the old pointers to the new array, then * if it exists at all, put the old array on the * Note that we can't kmem_free() the old array. * Why -- well the 'get' operation is 'mutex-free', so we * can't easily catch a suspended thread that is just about * to dereference the array we just grew out of. So we * cons up a header and put it on a list of 'dirty' * pointer arrays. (Dirty in the sense that there may * be suspended threads somewhere that are in the middle * of referencing them). Fortunately, we -can- garbage * collect it all at ddi_soft_state_fini time. * Copy the pointers into the new array * Save the old array on the dirty list * Fetch a pointer to the allocated soft state structure. * This is designed to be cheap. * There's an argument that there should be more checking for * nil pointers and out of bounds on the array.. but we do a lot * An array has the convenience that we don't need to lock read-access * to it c.f. a linked list. However our "expanding array" strategy * means that we should hold a readers lock on the i_ddi_soft_state * However, from a performance viewpoint, we need to do it without * any locks at all -- this also makes it a leaf routine. The algorithm * is 'lock-free' because we only discard the pointer arrays at * ddi_soft_state_fini() time. * Free the state structure corresponding to 'item.' Freeing an * element that has either gone or was never allocated is not * considered an error. Note that we free the state structure, but * we don't shrink our pointer array, or discard 'dirty' arrays, * since even a few pointers don't really waste too much memory. * Passing an item number that is out of bounds, or a null pointer will * provoke an error message. static char msg[] =
"ddi_soft_state_free:";
* Free the entire set of pointers, and any * soft state structures contained therein. * Note that we don't grab the ss->lock mutex, even though * we're inspecting the various fields of the data structure. * There is an implicit assumption that this routine will * never run concurrently with any of the above on this * particular state structure i.e. by the time the driver * calls this routine, there should be no other threads static char msg[] =
"ddi_soft_state_fini:";
* Now delete any dirty arrays from previous 'grow' operations * This sets the devi_addr entry in the dev_info structure 'dip' to 'name'. * Storage is double buffered to prevent updates during devi_addr use - * double buffering is adaquate for reliable ddi_deviname() consumption. * The double buffer is not freed until dev_info structure destruction * ddi_name_to_major: Returns the major number of a module given its name. * ddi_major_to_name: Returns the module name bound to a major number. * Return the name of the devinfo node pointed at by 'dip' in the buffer * pointed at by 'name.' A devinfo node is named as a result of calling * Note: the driver must be held before calling this function! * Use ddi_get_name_addr() without checking state so we get * a unit-address if we are called after ddi_set_name_addr() * by nexus DDI_CTL_INITCHILD code, but before completing * node promotion to DS_INITIALIZED. We currently have * two situations where we are called in this state: * o For framework processing of a path-oriented alias. * o If a SCSA nexus driver calls ddi_devid_register() * from it's tran_tgt_init(9E) implementation. * Spits out the name of device node, typically name@addr, for a given node, * using the driver name, not the nodename. * Used by match_parent. Not to be used elsewhere. * Given a dev_t, return the pathname of the corresponding device in the * buffer pointed at by "path." The buffer is assumed to be large enough * to hold the pathname of the device (MAXPATHLEN). * The pathname of a device is the pathname of the devinfo node to which * the device "belongs," concatenated with the character ':' and the name * of the minor node corresponding to the dev_t. If spec_type is 0 then * just the pathname of the devinfo node is returned without driving attach * of that node. For a non-zero spec_type, an attach is performed and a * search of the minor list occurs. * It is possible that the path associated with the dev_t is not * currently available in the devinfo tree. In order to have a * dev_t, a device must have been discovered before, which means * that the path is always in the instance tree. The one exception * to this is if the dev_t is associated with a pseudo driver, in * which case the device must exist on the pseudo branch of the * devinfo tree as a result of parsing .conf files. /* clone has no minor nodes, manufacture the path here */ /* extract instance from devt (getinfo(9E) DDI_INFO_DEVT2INSTANCE). */ /* if spec_type given we must drive attach and search minor nodes */ /* attach the path so we can search minors */ /* Add minorname to path. */ * Given a major number and an instance, return the path. * This interface does NOT drive attach. * Not in instance tree, find the instance on the per driver list and * construct path to instance via ddi_pathname(). This is how paths * down the 'pseudo' branch are constructed. /* Skip if instance does not match. */ * An ndi_hold_devi() does not prevent DS_INITIALIZED->DS_BOUND * node demotion, so it is not an effective way of ensuring * that the ddi_pathname result has a unit-address. Instead, * we reverify the node state after calling ddi_pathname(). /* can't reconstruct the path */ * Given the dip for a network interface return the ppa for that interface. * In all cases except GLD v0 drivers, the ppa == instance. * In the case of GLD v0 drivers, the ppa is equal to the attach order. * So for these drivers when the attach routine calls gld_register(), * the GLD framework creates an integer property called "gld_driver_ppa" * that can be queried here. * The only time this function is used is when a system is booting over nfs. * In this case the system has to resolve the pathname of the boot device * i_ddi_devi_set_ppa() should only be called from gld_register() * and only for GLD v0 drivers * Private DDI Console bell functions. /* check if the cache attributes are supported */ * Transfer the meaningful bits to xfermodes. * Double-check if the 3rd party driver correctly sets the bits. * If not, set DDI_DMA_STREAMING to keep compatibility. * initialize the common elements of data access handle * If the buffer has no proc pointer, or the proc * struct has the kernel address space, or the buffer has * been marked B_REMAPPED (meaning that it is now * mapped into the kernel's address space), then * the address space is kas (kernel address space). * register mapping routines. * Allocate and initialize the common elements of data access handle. * Set up the mapping request and call to parent. * Call my parent to unmap my regs. /* check for total byte count is multiple of data transfer size */ /* check for total byte count is multiple of data transfer size */ * Convert a binding name to a driver name. * A binding name is the name used to determine the driver for a * device - it may be either an alias for the driver or the name * Search for minor name that has specified dev_t and spec_type. * If spec_type is zero then any dev_t match works. Since we * are returning a pointer to the minor name string, we require the * caller to do the locking. * The did layered driver currently intentionally returns a * devinfo ptr for an underlying sd instance based on a did * dev_t. In this case it is not an error. * The did layered driver is associated with Sun Cluster. * Find the devt and spectype of the specified minor_name. * Return DDI_FAILURE if minor_name not found. Since we are * returning everything via arguments we can do the locking. /* deal with clone minor nodes */ * Make sure minor_name is a STREAMS driver. * We load the driver but don't attach to any instances. for (i = 0; i <
ndevs; i++) {
for (i = 0; i <
npaths; i++) {
for (i = 0; i <
ndevs; i++) {
* Register device id into DDI framework. * Must be called when device is attached. /* verify that the devid is valid */ /* Updating driver name hint in devid */ /* Pick up last four characters of driver name */ /* Corrupt the devid for testing. */ /* encode the devid as a string */ /* add string as a string property */ * marker for devinfo snapshot compatibility. * This code gets deleted when di_devid is gone from libdevid #
endif /* DEVID_COMPATIBILITY */ * Register devid in devid-to-path cache * Remove (unregister) device id from DDI framework. * Must be called when device is detached. * marker for micro release devinfo snapshot compatibility. * This code gets deleted for the minor release. #
endif /* DEVID_COMPATIBILITY */ /* remove the devid property */ * Allocate and initialize a device id. /* Fill in driver name hint */ /* Pick up last four characters of driver name */ /* increase the generation number */ /* Fill in host id (big-endian byte ordering) */ * Fill in timestamp (big-endian byte ordering) * (Note that the format may have to be changed * before 2038 comes around, though it's arguably * unique enough as it is..) /* fill in the generation number */ /* look up the property, devt specific first */ /* convert to binary form */ * Return a copy of the device id for dev_t * Return a copy of the minor name for dev_t and spec_type /* drop lock to allocate memory */ /* re-check things, since we dropped the lock */ /* verify size is the same */ /* sz == alloc_sz - make a copy */ * Note: This will need to be fixed if we ever allow processes to * have more than one data model per exec. * ddi interfaces managing storage and retrieval of eventcookies. * Invoke bus nexus driver's implementation of the * (*bus_remove_eventcall)() interface to remove a registered * callback handler for "event". * Invoke bus nexus driver's implementation of the * (*bus_add_eventcall)() interface to register a callback handler * Return a handle for event "name" by calling up the device tree * hierarchy via (*bus_get_eventcookie)() interface until claimed * by a bus nexus or top of dev_info tree is reached. * single thread access to dev_info node and set state * wait until state(s) have been changed * clear the state(s) and wakeup any threads waiting * This procedure is provided as the general callback function when * umem_lockmemory calls as_add_callback for long term memory locking. * When as_unmap, as_setprot, or as_free encounter segments which have * locked memory, this callback will be invoked. * Call the cleanup function. Decrement the cookie reference * count, if it goes to zero, return the memory for the cookie. * The i_ddi_umem_unlock for this cookie may or may not have been * called already. It is the responsibility of the caller of * umem_lockmemory to handle the case of the cleanup routine * being called after a ddi_umem_unlock for the cookie /* remove the cookie if reference goes to zero */ * The following two Consolidation Private routines provide generic * To keep project_rele and project_hold consistent, i_ddi_decr_locked_memory() * must be called every time i_ddi_incr_locked_memory() is called. * To keep project_rele and project_hold consistent, i_ddi_incr_locked_memory() * must be called every time i_ddi_decr_locked_memory() is called. * This routine checks if the max-locked-memory resource ctl is * exceeded, if not increments it, grabs a hold on the project. * Returns 0 if successful otherwise returns error code * Decrements the max-locked-memory resource ctl and releases * the hold on the project that was acquired during umem_incr_devlockmem * A consolidation private function which is essentially equivalent to * ddi_umem_lock but with the addition of arguments ops_vector and procp. * A call to as_add_callback is done if DDI_UMEMLOCK_LONGTERM is set, and * the ops_vector is valid. * Lock the virtual address range in the current process and create a * ddi_umem_cookie (of type UMEM_LOCKED). This can be used to pass to * Note: The resource control accounting currently uses a full charge model * will deduct the full size of the buffer from the projects running * counter for the device locked memory. * addr, size should be PAGESIZE aligned * flags - DDI_UMEMLOCK_READ, DDI_UMEMLOCK_WRITE or both * identifies whether the locked memory will be read or written or both * DDI_UMEMLOCK_LONGTERM must be set when the locking will * be maintained for an indefinitely long period (essentially permanent), * rather than for what would be required for a typical I/O completion. * When DDI_UMEMLOCK_LONGTERM is set, umem_lockmemory will return EFAULT * if the memory pertains to a regular file which is mapped MAP_SHARED. * This is to prevent a deadlock if a file truncation is attempted after * after the locking is done. * EINVAL - for invalid parameters * EPERM, ENOMEM and other error codes returned by as_pagelock * ENOMEM - is returned if the current request to lock memory exceeds * *.max-locked-memory resource control value. * EFAULT - memory pertains to a regular file mapped shared and * and DDI_UMEMLOCK_LONGTERM flag is set * EAGAIN - could not start the ddi_umem_unlock list processing thread /* These are the only three valid flags */ /* At least one (can be both) of the two access flags must be set */ /* addr and len must be page-aligned */ * For longterm locking a driver callback must be specified; if * not longterm then a callback is optional. * Call i_ddi_umem_unlock_thread_start if necessary. It will * be called on first ddi_umem_lock or umem_lockmemory call. /* Allocate memory for the cookie */ /* Convert the flags to seg_rw type */ * Store the struct as pointer in cookie for later use by * ddi_umem_unlock. The proc->p_as will be stale if ddi_umem_unlock * is called after relvm is called. * The size field is needed for lockmem accounting. * The requested memory cannot be locked /* Lock the pages corresponding to addr, len in memory */ * For longterm locking the addr must pertain to a seg_vn segment or * If the segment pertains to a regular file, it cannot be * This is to prevent a deadlock if a file truncation is attempted * after the locking is done. * Doing this after as_pagelock guarantees persistence of the as; if * an unacceptable segment is found, the cleanup includes calling * as_pageunlock before returning EFAULT. /* Initialize the fields in the ddi_umem_cookie */ /* i_ddi_umem_unlock and umem_lock_undo may need the cookie */ /* only i_ddi_umme_unlock needs the cookie */ * If a driver callback was specified, add an entry to the * as struct callback list. The as_pagelock above guarantees * Unlock the pages locked by ddi_umem_lock or umem_lockmemory and free * the cookie. Called from i_ddi_umem_unlock_thread. * There is no way to determine whether a callback to * umem_lock_undo was registered via as_add_callback. * (i.e. umem_lockmemory was called with DDI_MEMLOCK_LONGTERM and * a valid callback function structure.) as_delete_callback * is called to delete a possible registered callback. If the * return from as_delete_callbacks is AS_CALLBACK_DELETED, it * indicates that there was a callback registered, and that is was * successfully deleted. Thus, the cookie reference count * will never be decremented by umem_lock_undo. Just return the * memory for the cookie, since both users of the cookie are done. * A return of AS_CALLBACK_NOTFOUND indicates a callback was * never registered. A return of AS_CALLBACK_DELETE_DEFERRED * indicates that callback processing is taking place and, and * umem_lock_undo is, or will be, executing, and thus decrementing * the cookie reference count when it is complete. * This needs to be done before as_pageunlock so that the * persistence of as is guaranteed because of the locked pages. * The proc->p_as will be stale if i_ddi_umem_unlock is called * after relvm is called so use p->asp. * Now that we have unlocked the memory decrement the * *.max-locked-memory rctl /* umem_lock_undo will not happen, return the cookie memory */ * umem_undo_lock may happen if as_delete_callback returned * AS_CALLBACK_DELETE_DEFERRED. In that case, decrement the * reference count, atomically, and return the cookie * memory if the reference count goes to zero. The only * other value for rc is AS_CALLBACK_NOTFOUND. In that * case, just return the cookie memory. * i_ddi_umem_unlock_thread - deferred ddi_umem_unlock list handler. * Call i_ddi_umem_unlock for entries in the ddi_umem_unlock list * until it is empty. Then, wait for more to be added. This thread is awoken * via calls to ddi_umem_unlock. /* process the ddi_umem_unlock list */ /* take if off the list */ /* unlock the pages in this cookie */ }
else {
/* list is empty, wait for next ddi_umem_unlock */ /* ddi_umem_unlock_thread does not exit */ * Start the thread that will process the ddi_umem_unlock list if it is * not already started (i_ddi_umem_unlock_thread). * Lock the virtual address range in the current process and create a * ddi_umem_cookie (of type UMEM_LOCKED). This can be used to pass to * Note: The resource control accounting currently uses a full charge model * will deduct the full size of the buffer from the projects running * counter for the device locked memory. This applies to umem_lockmemory too. * addr, size should be PAGESIZE aligned * flags - DDI_UMEMLOCK_READ, DDI_UMEMLOCK_WRITE or both * identifies whether the locked memory will be read or written or both * EINVAL - for invalid parameters * EPERM, ENOMEM and other error codes returned by as_pagelock * ENOMEM - is returned if the current request to lock memory exceeds * *.max-locked-memory resource control value. * EAGAIN - could not start the ddi_umem_unlock list processing thread /* These are the only two valid flags */ /* At least one of the two flags (or both) must be set */ /* addr and len must be page-aligned */ * Call i_ddi_umem_unlock_thread_start if necessary. It will * be called on first ddi_umem_lock or umem_lockmemory call. /* Allocate memory for the cookie */ /* Convert the flags to seg_rw type */ * Store the struct as pointer in cookie for later use by * ddi_umem_unlock. The proc->p_as will be stale if ddi_umem_unlock * is called after relvm is called. * The size field is needed for lockmem accounting. * The requested memory cannot be locked /* Lock the pages corresponding to addr, len in memory */ /* Initialize the fields in the ddi_umem_cookie */ * Add the cookie to the ddi_umem_unlock list. Pages will be * unlocked by i_ddi_umem_unlock_thread. * Queue the unlock request and notify i_ddi_umem_unlock thread * if it's called in the interrupt context. Otherwise, unlock pages /* queue the unlock request and notify the thread */ /* unlock the pages right away */ * Create a buf structure from a ddi_umem_cookie * cookie - is a ddi_umem_cookie for from ddi_umem_lock and ddi_umem_alloc * (only UMEM_LOCKED & KMEM_NON_PAGEABLE types supported) * off, len - identifies the portion of the memory represented by the cookie * that the buf points to. * NOTE: off, len need to follow the alignment/size restrictions of the * device (dev) that this buf will be passed to. Some devices * will accept unrestricted alignment/size, whereas others (such as * are met (we cannot assert as we do not know the restrictions) * direction - is one of B_READ or B_WRITE and needs to be compatible with * the flags used in ddi_umem_lock * The following three arguments are used to initialize fields in the * buf structure and are uninterpreted by this routine. * sleepflag - is one of DDI_UMEM_SLEEP or DDI_UMEM_NOSLEEP * Returns a buf structure pointer on success (to be freed by freerbuf) * NULL on any parameter error or memory alloc failure * check for valid cookie offset, len /* direction has to be one of B_READ or B_WRITE */ /* These are the only two valid sleepflags */ * Only cookies of type UMEM_LOCKED and KMEM_NON_PAGEABLE are supported /* If type is KMEM_NON_PAGEABLE procp is NULL */ * Fault-handling and related routines * Assemble all the information into a fault-event-data structure * Get eventcookie from defining parent. * Task Queues DDI interfaces.