ddi_impl.c revision 19174f18ff621e2acd8b3e8f6a9504a68e5fd8f7
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
/*
* sun4 specific DDI implementation
*/
#include <sys/ddi_subrdefs.h>
#include <sys/machsystm.h>
#include <sys/sysmacros.h>
#include <vm/seg_kmem.h>
#include <sys/dditypes.h>
#include <sys/bootconf.h>
#include <sys/ethernet.h>
#include <sys/prom_plat.h>
#include <sys/systeminfo.h>
#pragma weak get_intr_parent
ddi_intr_handle_impl_t *, void *);
#pragma weak process_intr_ops
#pragma weak cells_1275_copy
/*
* Wrapper for ddi_prop_lookup_int_array().
* This is handy because it returns the prop length in
* bytes which is what most of the callers require.
*/
static int
{
int ret;
}
return (ret);
}
/*
* SECTION: DDI Node Configuration
*/
/*
* init_regspec_64:
*
* If the parent #size-cells is 2, convert the upa-style or
* safari-style reg property from 2-size cells to 1 size cell
* format, ignoring the size_hi, which must be zero for devices.
* (It won't be zero in the memory list properties in the memory
* nodes, but that doesn't matter here.)
*/
struct ddi_parent_private_data *
{
struct ddi_parent_private_data *pd;
int size_cells;
/*
* If there are no "reg"s in the child node, return.
*/
return (pd);
}
if (size_cells != 1) {
int n, j;
struct reg_64 {
};
int *reg_prop;
/*
* We already looked the property up once before if
* pd is non-NULL.
*/
n = sizeof (struct reg_64) / sizeof (int);
n = len / n;
/*
* We're allocating a buffer the size of the PROM's property,
* but we're only using a smaller portion when we assign it
* to a regspec. We do this so that in the
* impl_ddi_sunbus_removechild function, we will
* always free the right amount of memory.
*/
}
}
return (pd);
}
/*
* Create a ddi_parent_private_data structure from the ddi properties of
* the dev_info node.
*
* The "reg" is required if the driver wishes to create mappings on behalf
* of the device. The "reg" property is assumed to be a list of at least
* one triplet
*
* <bustype, address, size>*1
*
* The "interrupt" property is no longer part of parent private data on
* sun4u. The interrupt parent is may not be the device tree parent.
*
* The "ranges" property describes the mapping of child addresses to parent
* addresses.
*
* N.B. struct rangespec is defined for the following default values:
* parent child
* #address-cells 2 2
* #size-cells 1 1
* This function doesn't deal with non-default cells and will not create
* ranges in such cases.
*/
void
{
struct ddi_parent_private_data *pdptr;
/*
* root node has no parent private data, so *ppd should
* be initialized for naming to work properly.
*/
return;
/*
* Set reg field of parent data from "reg" property
*/
== DDI_PROP_SUCCESS) && (reg_len != 0)) {
}
/*
* "ranges" property ...
*
* This function does not handle cases where #address-cells != 2
* and * min(parent, child) #size-cells != 1 (see bugid 4211124).
*
* Nexus drivers with such exceptions (e.g. pci ranges)
* should either create a separate function for handling
* ranges or not use parent private data to store ranges.
*/
/* root node has no ranges */
return;
"#address-cells or #size-cells have non-default value"));
return;
}
== DDI_PROP_SUCCESS) {
}
}
/*
* Free ddi_parent_private_data structure
*/
void
{
return;
}
/*
* Name a child of sun busses based on the reg spec.
* Handles the following properties:
*
* Property value
* Name type
*
* reg register spec
* interrupts new (bus-oriented) interrupt spec
* ranges range spec
*
* This may be called multiple times, independent of
* initchild calls.
*/
static int
{
struct ddi_parent_private_data *pdptr;
/*
* Fill in parent-private data and this function returns to us
* an indication if it used "registers" to fill in the data.
*/
}
/*
* No reg property, return null string as address
* (e.g. root node)
*/
name[0] = '\0';
if (sparc_pd_getnreg(child) == 0) {
return (DDI_SUCCESS);
}
return (DDI_SUCCESS);
}
/*
* Called from the bus_ctl op of some drivers.
* to implement the DDI_CTLOPS_INITCHILD operation.
*
* NEW drivers should NOT use this function, but should declare
* there own initchild/uninitchild handlers. (This function assumes
* the layout of the parent private data and the format of "reg",
* "ranges", "interrupts" properties and that #address-cells and
* #size-cells of the parent bus are defined to be default values.)
*/
int
{
char name[MAXNAMELEN];
/*
* Try to merge .conf node. If successful, return failure to
* remove this child.
*/
if ((ndi_dev_is_persistent_node(child) == 0) &&
return (DDI_FAILURE);
}
return (DDI_SUCCESS);
}
/*
* A better name for this function would be impl_ddi_sunbus_uninitchild()
* It does not remove the child, it uninitializes it, reclaiming the
* resources taken by impl_ddi_sunbus_initchild.
*/
void
{
/*
* Strip the node to properly convert it back to prototype form
*/
}
/*
* SECTION: DDI Interrupt
*/
void
{
int i;
for (i = 0; i < len; i++)
}
{
prop_1275_cell_t *match_cell = 0;
int32_t i;
for (i = 0; i < len; i++)
match_cell = &cell1[i];
break;
}
return (match_cell);
}
/*
* get_intr_parent() is a generic routine that process a 1275 interrupt
* map (imap) property. This function returns a dev_info_t structure
* which claims ownership of the interrupt domain.
* It also returns the new interrupt translation within this new domain.
* If an interrupt-parent or interrupt-map property are not found,
* then we fallback to using the device tree's parent.
*
* imap entry format:
* <reg>,<interrupt>,<phandle>,<translated interrupt>
* reg - The register specification in the interrupts domain
* interrupt - The interrupt specification
* phandle - PROM handle of the device that owns the xlated interrupt domain
* translated interrupt - interrupt specifier in the parents domain
* note: <reg>,<interrupt> - The reg and interrupt can be combined to create
* a unique entry called a unit interrupt specifier.
*
* Here's the processing steps:
* step1 - If the interrupt-parent property exists, create the ispec and
* return the dip of the interrupt parent.
* step2 - Extract the interrupt-map property and the interrupt-map-mask
* If these don't exist, just return the device tree parent.
* step3 - build up the unit interrupt specifier to match against the
* interrupt map property
* step4 - Scan the interrupt-map property until a match is found
* step4a - Extract the interrupt parent
* step4b - Compare the unit interrupt specifier
*/
{
int32_t match_found = 0;
#ifdef DEBUG
static int debug = 0;
#endif
/*
* step1
* If we have an interrupt-parent property, this property represents
* the nodeid of our interrupt parent.
*/
"interrupt-parent", -1)) != -1) {
/*
* Attach the interrupt parent.
*
* N.B. e_ddi_nodeid_to_dip() isn't safe under DR.
* Also, interrupt parent isn't held. This needs
* to be revisited if DR-capable platforms implement
* interrupt redirection.
*/
!= DDI_SUCCESS) {
return (NULL);
}
return (intr_parent_dip);
}
/*
* step2
* Get interrupt map structure from PROM property
*/
!= DDI_PROP_SUCCESS) {
/*
* If we don't have an imap property, default to using the
* device tree.
*/
return (pdip);
}
/* Get the interrupt mask property */
!= DDI_PROP_SUCCESS) {
/*
* If we don't find this property, we have to fail the request
* because the 1275 imap property wasn't defined correctly.
*/
goto exit2;
}
/* Get the address cell size */
"#address-cells", 2);
/* Get the interrupts cell size */
"#interrupt-cells", 1);
/*
* step3
* Now lets build up the unit interrupt specifier e.g. reg,intr
* and apply the imap mask. match_req will hold this when we're
* through.
*/
goto exit3;
}
for (i = 0; i < addr_cells; i++)
for (j = 0; j < intr_cells; i++, j++)
/* Calculate the imap size in cells */
#ifdef DEBUG
if (debug)
prom_printf("reg cell size 0x%x, intr cell size 0x%x, "
#endif
/*
* Scan the imap property looking for a match of the interrupt unit
* specifier. This loop is rather complex since the data within the
* imap property may vary in size.
*/
int new_intr_cells;
/* Set the index to the nodeid field */
i = addr_cells + intr_cells;
/*
* step4a
* Translate the nodeid field to a dip
*/
ASSERT(intr_parent_dip != 0);
#ifdef DEBUG
if (debug)
#endif
/*
* The tmp_dip describes the new domain, get it's interrupt
* cell size
*/
"#interrupts-cells", 1);
/*
* step4b
* See if we have a match on the interrupt unit specifier
*/
== 0) {
match_found = 1;
/*
* If we have an imap parent whose not in our device
* tree path, we need to hold and install that driver.
*/
!= DDI_SUCCESS) {
goto exit4;
}
/*
* We need to handcraft an ispec along with a bus
* interrupt value, so we can dup it into our
* standard ispec structure.
*/
/* Extract the translated interrupt information */
intr = kmem_alloc(
for (j = 0; j < new_intr_cells; j++, i++)
#ifdef DEBUG
if (debug)
#endif
break;
} else {
#ifdef DEBUG
if (debug)
#endif
i += new_intr_cells;
}
}
/*
* If we haven't found our interrupt parent at this point, fallback
* to using the device tree.
*/
if (!match_found) {
}
return (intr_parent_dip);
}
/*
* process_intr_ops:
*
* Process the interrupt op via the interrupt parent.
*/
int
{
int ret = DDI_FAILURE;
if (NEXUS_HAS_INTR_OP(pdip)) {
} else {
"for %s%d due to down-rev nexus driver %s%d",
}
return (ret);
}
/*ARGSUSED*/
{
softint();
return (1);
}
/*
* indirection table, to save us some large switch statements
* NOTE: This must agree with "INTLEVEL_foo" constants in
*/
struct autovec *const vectorlist[] = { 0 };
/*
* This value is exported here for the functions in avintr.c
*/
/*
* Check for machine specific interrupt levels which cannot be reassigned by
* settrap(), sun4u version.
*
* sun4u does not support V8 SPARC "fast trap" handlers.
*/
/*ARGSUSED*/
int
exclude_settrap(int lvl)
{
return (1);
}
/*
* Check for machine specific interrupt levels which cannot have interrupt
* handlers added. We allow levels 1 through 15; level 0 is nonsense.
*/
/*ARGSUSED*/
int
exclude_level(int lvl)
{
}
/*
* Wrapper functions used by New DDI interrupt framework.
*/
/*
* i_ddi_intr_ops:
*/
int
{
int ret = DDI_FAILURE;
/*
* The following check is required to address
* one of the test case of ADDI test suite.
*/
return (DDI_FAILURE);
switch (op) {
case DDI_INTROP_ADDISR:
case DDI_INTROP_REMISR:
case DDI_INTROP_ENABLE:
case DDI_INTROP_DISABLE:
case DDI_INTROP_BLOCKENABLE:
case DDI_INTROP_BLOCKDISABLE:
/*
* Try and determine our parent and possibly an interrupt
* translation. intr parent dip returned held
*/
goto done;
}
done:
switch (op) {
case DDI_INTROP_ADDISR:
case DDI_INTROP_REMISR:
case DDI_INTROP_ENABLE:
case DDI_INTROP_DISABLE:
case DDI_INTROP_BLOCKENABLE:
case DDI_INTROP_BLOCKDISABLE:
/* Release hold acquired in get_intr_parent() */
if (pdip)
}
return (ret);
}
/*
* i_ddi_add_ivintr:
*/
/*ARGSUSED*/
int
{
/*
* If the PIL was set and is valid use it, otherwise
* default it to 1
*/
return (DDI_SUCCESS);
}
/*
* i_ddi_rem_ivintr:
*/
/*ARGSUSED*/
void
{
}
/*
* i_ddi_get_inum - Get the interrupt number property from the
* specified device. Note that this function is called only for
* the FIXED interrupt type.
*/
{
"#interrupt-cells", 1);
/* adjust for number of bytes */
/* Calculate the number of interrupts */
/* Index into interrupt property */
}
}
return (intr);
}
/*
* i_ddi_get_intr_pri - Get the interrupt-priorities property from
* the specified device. Note that this function is called only for
* the FIXED interrupt type.
*/
{
int32_t i;
/*
* Use the "interrupt-priorities" property to determine the
*/
&i) == DDI_SUCCESS) {
kmem_free(intr_prio_p, i);
}
return (pri);
}
int
{
"#interrupt-cells", 1);
/* adjust for number of bytes */
}
return (ret);
}
/*
* i_ddi_add_softint - allocate and add a software interrupt.
*
* NOTE: All software interrupts that are registered through DDI
* should be triggered only on a single target or CPU.
*/
int
{
return (DDI_FAILURE);
return (DDI_SUCCESS);
}
/*
* i_ddi_remove_softint - remove and free a software interrupt.
*/
void
{
}
/*
* i_ddi_trigger_softint - trigger a software interrupt.
*/
int
{
int ret;
/* Update the second argument for the software interrupt */
}
/*
* i_ddi_set_softint_pri - change software interrupt priority.
*/
/* ARGSUSED */
int
{
int ret;
/* Update the interrupt priority for the software interrupt */
}
/*ARGSUSED*/
void
{
}
/*ARGSUSED*/
void
{
}
/*
*/
/* set HAT endianess attributes from ddi_device_acc_attr */
void
{
*hataccp &= ~HAT_ENDIAN_MASK;
*hataccp |= HAT_STRUCTURE_LE;
}
}
}
/*
* Check if the specified cache attribute is supported on the platform.
* This function must be called before i_ddi_cacheattr_to_hatacc().
*/
{
/*
* The cache attributes are mutually exclusive. Any combination of
* the attributes leads to a failure.
*/
return (B_FALSE);
/*
* On the sparc architecture, only IOMEM_DATA_CACHED is meaningful,
* but others lead to a failure.
*/
if (cache_attr & IOMEM_DATA_CACHED)
return (B_TRUE);
else
return (B_FALSE);
}
/* set HAT cache attributes from the cache attributes */
void
{
static char *fname = "i_ddi_cacheattr_to_hatacc";
#if defined(lint)
#endif
/*
* set HAT attrs according to the cache attrs.
*/
switch (cache_attr) {
/*
* The cache coherency is always maintained on SPARC, and
* nothing is required.
*/
case IOMEM_DATA_CACHED:
break;
/*
* Both IOMEM_DATA_UC_WRITE_COMBINED and IOMEM_DATA_UNCACHED are
* not supported on SPARC -- this case must not occur because the
* cache attribute is scrutinized before this function is called.
*/
case IOMEM_DATA_UNCACHED:
case IOMEM_DATA_UC_WR_COMBINE:
default:
fname, cache_attr);
}
}
static vmem_t *little_endian_arena;
static vmem_t *big_endian_arena;
static void *
{
}
static void *
{
}
void
ka_init(void)
{
}
/*
* Allocate from the system, aligned on a specific boundary.
* The alignment, if non-zero, must be a power of 2.
*/
static void *
{
/*
* We need to allocate
* rsize = size + hdrsize + align - MIN(hdrsize, buffer_alignment)
* bytes to be sure we have enough freedom to satisfy the request.
* Since the buffer alignment depends on the request size, this is
* not straightforward to use directly.
*
* kmem guarantees that any allocation of a 64-byte multiple will be
* 64-byte aligned. Since rounding up the request could add more
* than we save, we compute the size with and without alignment, and
* use the smaller of the two.
*/
if (endian_flags == DDI_STRUCTURE_LE_ACC) {
} else {
}
return (NULL);
return (addr);
}
static void
{
else
}
int
{
caddr_t a;
#if defined(lint)
#endif
/*
* Check legality of arguments
*/
return (DDI_FAILURE);
}
return (DDI_FAILURE);
}
/*
* check if a streaming sequential xfer is requested.
*/
/*
* Drivers for 64-bit capable SBus devices will encode
* the burtsizes for 64-bit xfers in the upper 16-bits.
* For DMA alignment, we use the most restrictive
* alignment of 32-bit and 64-bit xfers.
*/
/*
* If a driver set burtsizes to 0, we give him byte alignment.
* Otherwise align at the burtsizes boundary.
*/
if (iomin == 0)
iomin = 1;
else
if (iomin == 0)
return (DDI_FAILURE);
if ((*kaddrp = a) == 0) {
return (DDI_FAILURE);
} else {
if (real_length) {
*real_length = length;
}
if (handlep) {
/*
* assign handle information
*/
}
return (DDI_SUCCESS);
}
}
/*
* covert old DMA limits structure to DMA attribute structure
* and continue
*/
int
{
int ret;
attrp->dma_attr_flags = 0;
if (ret == DDI_SUCCESS) {
if (real_length)
}
return (ret);
}
/* ARGSUSED */
void
{
}
/*
* SECTION: DDI Data Access
*/
static uintptr_t impl_acc_hdl_id = 0;
/*
* access handle allocator
*/
{
/*
* Extract the access handle address from the DDI implemented
* access handle
*/
}
{
int sleepflag;
/*
* Allocate and initialize the data access handle and error status.
*/
goto fail;
goto fail;
}
goto fail;
}
return ((ddi_acc_handle_t)hp);
fail:
(waitfp != (int (*)())KM_NOSLEEP))
return (NULL);
}
void
{
/*
* The supplied (ddi_acc_handle_t) is actually a (ddi_acc_impl_t *),
* because that's what we allocated in impl_acc_hdl_alloc() above.
*/
if (hp) {
if (impl_acc_hdl_id)
}
}
/*
* Function called after a dma fault occurred to find out whether the
* fault address is associated with a driver that is able to handle faults
* and recover from faults.
*/
/* ARGSUSED */
int
const void *not_used)
{
/*
* The driver has to set DDI_DMA_FLAGERR to recover from dma faults.
*/
int page;
return (DDI_FM_NONFATAL);
}
return (DDI_FM_UNKNOWN);
}
/*
* Function used to check if a given access handle owns the failing address.
* Called by ndi_fmc_error, when we detect a PIO error.
*/
/* ARGSUSED */
static int
const void *not_used)
{
return (DDI_FM_NONFATAL);
}
return (DDI_FM_UNKNOWN);
}
void
{
int fmcap;
!DDI_FM_ACC_ERR_CAP(fmcap)) {
} else if (DDI_FM_ACC_ERR_CAP(fmcap)) {
NULL, DDI_NOSLEEP);
} else {
otp->ot_trampoline =
else
otp->ot_trampoline =
}
}
}
void
{
/*
* check for SW byte-swapping
*/
} else {
}
/* Legacy fault flags and support */
}
void
{
}
}
void
{
}
}
/* ARGSUSED */
void
{
/* Default version, does nothing */
}
/*
* SECTION: Misc functions
*/
/*
* instance wrappers
*/
/*ARGSUSED*/
{
return ((uint_t)-1);
}
/*ARGSUSED*/
int
{
return (DDI_FAILURE);
}
/*ARGSUSED*/
int
{
return (DDI_FAILURE);
}
/*ARGSUSED*/
int
{
return (DDI_SUCCESS);
}
static const char *nocopydevs[] = {
"SUNW,ffb",
"SUNW,afb",
};
/*
* Perform a copy from a memory mapped device (whose devinfo pointer is devi)
* separately mapped at devaddr in the kernel to a kernel buffer at kaddr.
*/
/*ARGSUSED*/
int
{
const char **argv;
return (0);
}
return (0);
}
/*
* Perform a copy to a memory mapped device (whose devinfo pointer is devi)
* separately mapped at devaddr in the kernel from a kernel buffer at kaddr.
*/
/*ARGSUSED*/
int
{
const char **argv;
return (1);
return (0);
}
/*
* Boot Configuration
*/
/*
* Configure the hardware on the system.
* Called before the rootfs is mounted
*/
void
configure(void)
{
extern void i_ddi_init_root();
/* We better have released boot by this time! */
/*
* Determine whether or not to use the fpu, V9 SPARC cpus
* always have one. Could check for existence of a fp queue,
* Ultra I, II and IIa do not have a fp queue.
*/
if (fpu_exists)
fpu_probe();
else
#if 0 /* XXXQ - not necessary for sun4u */
/*
* This following line fixes bugid 1041296; we need to do a
* prom_nextnode(0) because this call ALSO patches the DMA+
* bug in Campus-B and Phoenix. The prom uncaches the traptable
* page as a side-effect of devr_next(0) (which prom_nextnode calls),
* so this *must* be executed early on. (XXX This is untrue for sun4u)
*/
(void) prom_nextnode((pnode_t)0);
#endif
/*
* Initialize devices on the machine.
* Uses configuration tree built by the PROMs to determine what
* is present, and builds a tree of prototype dev_info nodes
* corresponding to the hardware which identified itself.
*/
#ifdef DDI_PROP_DEBUG
#endif /* DDI_PROP_DEBUG */
}
/*
* The "status" property indicates the operational status of a device.
* If this property is present, the value is a string indicating the
* status of the device as follows:
*
* "okay" operational.
* "disabled" not operational, but might become operational.
* "fail" not operational because a fault has been detected,
* and it is unlikely that the device will become
* operational without repair. no additional details
* are available.
* "fail-xxx" not operational because a fault has been detected,
* and it is unlikely that the device will become
* operational without repair. "xxx" is additional
* human-readable information about the particular
* fault condition that was detected.
*
* The absence of this property means that the operational status is
* unknown or okay.
*
* This routine checks the status property of the specified device node
* and returns 0 if the operational status indicates failure, and 1 otherwise.
*
* The property may exist on plug-in cards the existed before IEEE 1275-1994.
* And, in that case, the property may not even be a string. So we carefully
* check for the value "fail", in the beginning of the string, noting
* the property length.
*/
int
{
char status_buf[OBP_MAXPROPNAME];
int proplen;
static const char *status = "status";
static const char *fail = "fail";
/*
* Get the proplen ... if it's smaller than "fail",
* or doesn't exist ... then we don't care, since
* the value can't begin with the char string "fail".
*
* NB: proplen, if it's a string, includes the NULL in the
* the size of the property, and fail_len does not.
*/
return (1);
/*
* if a buffer was provided, use it
*/
bufp = status_buf;
len = sizeof (status_buf);
}
*bufp = (char)0;
/*
* Get the property into the buffer, to the extent of the buffer,
* and in case the buffer is smaller than the property size,
* NULL terminate the buffer. (This handles the case where
* a buffer was passed in and the caller wants to print the
* value, but the buffer was too small).
*/
/*
* If the value begins with the char string "fail",
* then it means the node is failed. We don't care
* about any other values. We assume the node is ok
* although it might be 'disabled'.
*/
return (0);
return (1);
}
/*
* We set the cpu type from the idprom, if we can.
* Note that we just read out the contents of it, for the most part.
*/
void
setcputype(void)
{
/*
* We cache the idprom info early on so that we don't
* rummage through the NVRAM unnecessarily later.
*/
}
/*
* Here is where we actually infer meanings to the members of idprom_t
*/
void
parse_idprom(void)
{
uint_t i;
(struct ether_addr *)NULL);
} else
prom_printf("Invalid format code in IDprom.\n");
}
/*
* Allow for implementation specific correction of PROM property values.
*/
/*ARGSUSED*/
void
{
/*
* There are no adjustments needed in this implementation.
*/
}
/*
* The following functions ready a cautious request to go up to the nexus
* driver. It is up to the nexus driver to decide how to process the request.
* It may choose to call i_ddi_do_caut_get/put in this file, or do it
* differently.
*/
static void
{
}
{
return (value);
}
{
return (value);
}
{
return (value);
}
{
return (value);
}
void
{
}
void
{
}
void
{
}
void
{
}
void
{
}
void
{
}
void
{
}
void
{
}
void
{
}
void
{
}
void
{
}
void
{
}
/*
* Assume that this is for memory, as nexi take care of device safe accesses.
*/
int
{
int err = DDI_SUCCESS;
/* Set up protected environment. */
if (cmd == DDI_CTLOPS_POKE) {
} else {
}
} else
err = DDI_FAILURE;
/* Take down protected environment. */
no_trap();
return (err);
}
/*
* Platform independent DR routines
*/
static int
ndi2errno(int n)
{
int err = 0;
switch (n) {
case NDI_NOMEM:
break;
case NDI_BUSY:
break;
case NDI_FAULT:
break;
case NDI_FAILURE:
break;
case NDI_SUCCESS:
break;
case NDI_BADHANDLE:
default:
break;
}
return (err);
}
/*
* Prom tree node list
*/
struct ptnode {
};
/*
* Prom tree walk arg
*/
struct pta {
};
static void
{
;
}
return;
}
}
/*ARGSUSED*/
static int
{
if (!DEVI_IS_DEVICE_OFFLINE(dip))
return (DDI_WALK_CONTINUE);
}
/*ARGSUSED*/
static int
{
int circ, c;
"nodeid: 0x%x", nodeid);
return (EINVAL);
}
}
return (ENODEV);
rv = 0;
/*
* Check if the branch already exists.
*/
exists = 0;
exists = 1;
/* Parent is held busy, so release hold */
#ifdef DEBUG
#endif
} else {
}
continue;
}
/*
* Hold the branch if it is not already held
*/
if (!exists)
/*
* Set all dips in the branch offline so that
* only a "configure" operation can attach
* the branch
*/
ndi_devi_enter(dip, &c);
ndi_devi_exit(dip, c);
}
/*
* Invoke devi_branch_callback() (if it exists) only for
* newly created branches
*/
}
return (rv);
}
static int
{
int i, flags;
char *nbuf;
static const char *noname = "<none>";
flags = 0;
/*
* Creating the root of a branch ?
*/
if (rdipp) {
}
if (rv == DDI_WALK_ERROR) {
" properties on devinfo node %p", (void *)dip);
goto fail;
}
!= DDI_PROP_SUCCESS) {
"no name property", (void *)dip);
goto fail;
}
goto fail;
}
/*
* Ignore bind failures just like boot does
*/
(void) ndi_devi_bind_driver(dip, 0);
switch (rv) {
case DDI_WALK_CONTINUE:
case DDI_WALK_PRUNESIB:
i = DDI_WALK_CONTINUE;
for (; i == DDI_WALK_CONTINUE; ) {
}
if (i == DDI_WALK_ERROR)
rv = i;
/*
* If PRUNESIB stop creating siblings
* of dip's child. Subsequent walk behavior
* is determined by rv returned by dip.
*/
break;
case DDI_WALK_TERMINATE:
/*
* Don't create children and ask our parent
* to not create siblings either.
*/
break;
case DDI_WALK_PRUNECHILD:
/*
* Don't create children, but ask parent to continue
* with siblings.
*/
break;
default:
ASSERT(0);
break;
}
if (rdipp)
/*
* Set device offline - only the "configure" op should cause an attach
*/
return (rv);
fail:
(void) ndi_devi_free(dip);
return (DDI_WALK_ERROR);
}
static int
dev_info_t **dipp,
{
while (state == DDI_WALK_CONTINUE) {
int circ;
break;
}
if (flags & DEVI_BRANCH_CONFIGURE) {
}
/*
* devi_branch_callback() is optional
*/
if (bp->devi_branch_callback)
}
}
int
dev_info_t **dipp,
{
return (EINVAL);
return (EINVAL);
return (EINVAL);
return (EINVAL);
if (flags & DEVI_BRANCH_EVENT)
return (EINVAL);
if (prom_devi) {
if (dipp)
} else {
}
return (error);
}
int
{
char *devnm;
if (dipp)
return (EINVAL);
if (!e_ddi_branch_held(rdip)) {
"dip(%p) not held", (void *)rdip);
return (EINVAL);
}
/*
* First attempt to bind a driver. If we fail, return
* success (On some platforms, dips for some device
* types (CPUs) may not have a driver)
*/
return (0);
}
rv = NDI_FAILURE;
goto out;
}
}
/* release hold from ndi_devi_config_one() */
}
out:
}
}
void
{
if (e_ddi_branch_held(rdip)) {
return;
}
}
}
int
{
int rv = 0;
rv = 1;
}
return (rv);
}
void
{
}
int
dev_info_t **dipp,
{
int destroy;
char *devnm;
if (dipp)
return (EINVAL);
/*
* Check if caller holds pdip busy - can cause deadlocks during
* devfs_clean()
*/
if (DEVI_BUSY_OWNED(pdip)) {
" devinfo node(%p) is busy held", (void *)pdip);
return (EINVAL);
}
/*
* ddi_deviname() returns a component name with / prepended.
*/
/*
* when parent busy lock was dropped for devfs_clean()
*/
if (!e_ddi_branch_held(rdip)) {
return (EINVAL);
}
/*
* Release hold on the branch. This is ok since we are holding the
* parent busy. If rdip is not removed, we must do a hold on the
* branch before returning.
*/
destroy = 1;
} else {
}
if (flags & DEVI_BRANCH_EVENT)
nflags |= NDI_POST_EVENT;
if (i_ddi_devi_attached(pdip) &&
} else {
if (rv == NDI_SUCCESS) {
}
}
/* The dip still exists, so do a hold */
}
out:
}
int
{
}
/*
* Number of chains for hash table
*/
#define NUMCHAINS 17
/*
* Devinfo busy arg
*/
struct devi_busy {
int dv_total;
int s_total;
void *arg;
};
static int
{
/*
* A dip cannot be busy if its reference count is 0
*/
}
dvbusy = 0;
/*
* To catch device opens currently maintained on specfs common snodes.
*/
sbusy = 0;
#ifdef DEBUG
}
#endif
}
static int
{
int count;
/*
* The stable lock is held. This prevents
* the snode and its associated dip from
* going away.
*/
if (count <= 0)
return (DDI_WALK_CONTINUE);
else
"sbusy = %lu", "e_ddi_branch_referenced",
}
return (DDI_WALK_CONTINUE);
}
static void
{
if (!count)
return;
(mod_hash_val_t *)&dvbusy))
else
(mod_hash_val_t)dvbusy)) {
"dvbusy=%lu", "e_ddi_branch_referenced",
}
}
/*
* Returns reference count on success or -1 on failure.
*/
int
void *arg)
{
int circ;
char *path;
/*
* Check if caller holds pdip busy - can cause deadlocks during
* devfs_walk()
*/
"devinfo branch(%p) not held or parent busy held",
(void *)rdip);
return (-1);
}
mod_hash_null_valdtor, sizeof (struct dev_info));
mod_hash_null_valdtor, sizeof (struct snode));
"devfs walk failed for: %s", path);
goto out;
}
/*
* Walk the snode table to detect device opens, which are currently
* maintained on specfs common snodes.
*/
goto out;
}
out:
}