root/usr/src/uts/intel/io/cpunex.c
/*
 * 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
 * or http://www.opensolaris.org/os/licensing.
 * 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 2008 Sun Microsystems, Inc.  All rights reserved.
 * Use is subject to license terms.
 */


/*
 * CPU nexus driver
 */

#include        <sys/types.h>
#include        <sys/param.h>
#include        <sys/conf.h>
#include        <sys/devops.h>
#include        <sys/modctl.h>
#include        <sys/cmn_err.h>
#include        <sys/ddi.h>
#include        <sys/sunddi.h>
#include        <sys/sunndi.h>

static int cpunex_attach(dev_info_t *, ddi_attach_cmd_t);
static int cpunex_detach(dev_info_t *, ddi_detach_cmd_t);
static int cpunex_bus_ctl(dev_info_t *, dev_info_t *, ddi_ctl_enum_t,
    void *, void *);

static struct bus_ops cpunex_bus_ops = {
        BUSO_REV,
        nullbusmap,
        NULL,
        NULL,
        NULL,
        i_ddi_map_fault,
        ddi_no_dma_map,
        ddi_no_dma_allochdl,
        ddi_no_dma_freehdl,
        ddi_no_dma_bindhdl,
        ddi_no_dma_unbindhdl,
        ddi_no_dma_flush,
        ddi_no_dma_win,
        ddi_no_dma_mctl,
        cpunex_bus_ctl,
        ddi_bus_prop_op,
};

static struct dev_ops cpunex_ops = {
        DEVO_REV,
        0,
        ddi_no_info,
        nulldev,
        nulldev,
        cpunex_attach,
        cpunex_detach,
        nodev,
        NULL,
        &cpunex_bus_ops,
        NULL,
        ddi_quiesce_not_needed,         /* quiesce */
};

static struct modldrv modldrv = {
        &mod_driverops,
        "cpu nexus driver",
        &cpunex_ops
};

static struct modlinkage modlinkage = {
        MODREV_1,
        &modldrv,
        NULL
};

/*
 * cpunex_bus_ctl()
 *    This routine implements nexus bus ctl operations. Of importance are
 *    DDI_CTLOPS_REPORTDEV, DDI_CTLOPS_INITCHILD, DDI_CTLOPS_UNINITCHILD
 *    and DDI_CTLOPS_POWER. For DDI_CTLOPS_INITCHILD, it tries to lookup
 *    reg property on the child node and builds and sets the name.
 */
static int
cpunex_bus_ctl(dev_info_t *dip, dev_info_t *rdip, ddi_ctl_enum_t op, void *arg,
    void *result)
{
        switch (op) {
                case DDI_CTLOPS_REPORTDEV: {
                        dev_info_t *pdip = ddi_get_parent(rdip);
                        cmn_err(CE_CONT, "?%s%d at %s%d",
                            ddi_node_name(rdip), ddi_get_instance(rdip),
                            ddi_node_name(pdip), ddi_get_instance(pdip));
                        return (DDI_SUCCESS);
                }

                case DDI_CTLOPS_INITCHILD: {
                        dev_info_t *cdip = (dev_info_t *)arg;
                        int i;
                        char caddr[MAXNAMELEN];

                        i = ddi_prop_get_int(DDI_DEV_T_ANY, cdip,
                            DDI_PROP_DONTPASS, "reg", -1);

                        if (i == -1) {
                                cmn_err(CE_NOTE, "!%s(%d): \"reg\" property "
                                    "not found", ddi_node_name(cdip),
                                    ddi_get_instance(cdip));
                                return (DDI_NOT_WELL_FORMED);
                        }

                        (void) sprintf(caddr, "%d", i);
                        ddi_set_name_addr(cdip, caddr);

                        return (DDI_SUCCESS);
                }

                case DDI_CTLOPS_UNINITCHILD: {
                        ddi_prop_remove_all((dev_info_t *)arg);
                        ddi_set_name_addr((dev_info_t *)arg, NULL);
                        return (DDI_SUCCESS);
                }

                default: {
                        return (ddi_ctlops(dip, rdip, op, arg, result));
                }
        }
}

/*ARGSUSED*/
static int
cpunex_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
{
        switch (cmd) {
        case DDI_ATTACH:
        case DDI_RESUME:
                break;
        default:
                return (DDI_FAILURE);
        }

        return (DDI_SUCCESS);
}

/*ARGSUSED*/
static int
cpunex_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
{
        switch (cmd) {
        case DDI_DETACH:
        case DDI_SUSPEND:
                break;
        default:
                return (DDI_FAILURE);
        }

        return (DDI_SUCCESS);
}

int
_init(void)
{
        int error;

        error = mod_install(&modlinkage);
        return (error);
}

int
_fini(void)
{
        int error;

        error = mod_remove(&modlinkage);
        return (error);
}

int
_info(struct modinfo *modinfop)
{
        return (mod_info(&modlinkage, modinfop));
}