1 /*
   2  * CDDL HEADER START
   3  *
   4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 /*
  22  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
  23  * Use is subject to license terms.
  24  */
  25 
  26 
  27 /*
  28  * CPU nexus driver
  29  */
  30 
  31 #include        <sys/types.h>
  32 #include        <sys/param.h>
  33 #include        <sys/conf.h>
  34 #include        <sys/devops.h>
  35 #include        <sys/modctl.h>
  36 #include        <sys/cmn_err.h>
  37 #include        <sys/ddi.h>
  38 #include        <sys/sunddi.h>
  39 #include        <sys/sunndi.h>
  40 
  41 static int cpunex_attach(dev_info_t *, ddi_attach_cmd_t);
  42 static int cpunex_detach(dev_info_t *, ddi_detach_cmd_t);
  43 static int cpunex_bus_ctl(dev_info_t *, dev_info_t *, ddi_ctl_enum_t,
  44     void *, void *);
  45 
  46 static struct bus_ops cpunex_bus_ops = {
  47         BUSO_REV,
  48         nullbusmap,
  49         NULL,
  50         NULL,
  51         NULL,
  52         i_ddi_map_fault,
  53         ddi_no_dma_map,
  54         ddi_no_dma_allochdl,
  55         ddi_no_dma_freehdl,
  56         ddi_no_dma_bindhdl,
  57         ddi_no_dma_unbindhdl,
  58         ddi_no_dma_flush,
  59         ddi_no_dma_win,
  60         ddi_no_dma_mctl,
  61         cpunex_bus_ctl,
  62         ddi_bus_prop_op,
  63 };
  64 
  65 static struct dev_ops cpunex_ops = {
  66         DEVO_REV,
  67         0,
  68         ddi_no_info,
  69         nulldev,
  70         nulldev,
  71         cpunex_attach,
  72         cpunex_detach,
  73         nodev,
  74         NULL,
  75         &cpunex_bus_ops,
  76         NULL,
  77         ddi_quiesce_not_needed,         /* quiesce */
  78 };
  79 
  80 static struct modldrv modldrv = {
  81         &mod_driverops,
  82         "cpu nexus driver",
  83         &cpunex_ops
  84 };
  85 
  86 static struct modlinkage modlinkage = {
  87         MODREV_1,
  88         &modldrv,
  89         NULL
  90 };
  91 
  92 /*
  93  * cpunex_bus_ctl()
  94  *    This routine implements nexus bus ctl operations. Of importance are
  95  *    DDI_CTLOPS_REPORTDEV, DDI_CTLOPS_INITCHILD, DDI_CTLOPS_UNINITCHILD
  96  *    and DDI_CTLOPS_POWER. For DDI_CTLOPS_INITCHILD, it tries to lookup
  97  *    reg property on the child node and builds and sets the name.
  98  */
  99 static int
 100 cpunex_bus_ctl(dev_info_t *dip, dev_info_t *rdip, ddi_ctl_enum_t op, void *arg,
 101     void *result)
 102 {
 103         switch (op) {
 104                 case DDI_CTLOPS_REPORTDEV: {
 105                         dev_info_t *pdip = ddi_get_parent(rdip);
 106                         cmn_err(CE_CONT, "?%s%d at %s%d",
 107                             ddi_node_name(rdip), ddi_get_instance(rdip),
 108                             ddi_node_name(pdip), ddi_get_instance(pdip));
 109                         return (DDI_SUCCESS);
 110                 }
 111 
 112                 case DDI_CTLOPS_INITCHILD: {
 113                         dev_info_t *cdip = (dev_info_t *)arg;
 114                         int i;
 115                         char caddr[MAXNAMELEN];
 116 
 117                         i = ddi_prop_get_int(DDI_DEV_T_ANY, cdip,
 118                             DDI_PROP_DONTPASS, "reg", -1);
 119 
 120                         if (i == -1) {
 121                                 cmn_err(CE_NOTE, "!%s(%d): \"reg\" property "
 122                                     "not found", ddi_node_name(cdip),
 123                                     ddi_get_instance(cdip));
 124                                 return (DDI_NOT_WELL_FORMED);
 125                         }
 126 
 127                         (void) sprintf(caddr, "%d", i);
 128                         ddi_set_name_addr(cdip, caddr);
 129 
 130                         return (DDI_SUCCESS);
 131                 }
 132 
 133                 case DDI_CTLOPS_UNINITCHILD: {
 134                         ddi_prop_remove_all((dev_info_t *)arg);
 135                         ddi_set_name_addr((dev_info_t *)arg, NULL);
 136                         return (DDI_SUCCESS);
 137                 }
 138 
 139                 default: {
 140                         return (ddi_ctlops(dip, rdip, op, arg, result));
 141                 }
 142         }
 143 }
 144 
 145 /*ARGSUSED*/
 146 static int
 147 cpunex_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
 148 {
 149         switch (cmd) {
 150         case DDI_ATTACH:
 151         case DDI_RESUME:
 152                 break;
 153         default:
 154                 return (DDI_FAILURE);
 155         }
 156 
 157         return (DDI_SUCCESS);
 158 }
 159 
 160 /*ARGSUSED*/
 161 static int
 162 cpunex_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
 163 {
 164         switch (cmd) {
 165         case DDI_DETACH:
 166         case DDI_SUSPEND:
 167                 break;
 168         default:
 169                 return (DDI_FAILURE);
 170         }
 171 
 172         return (DDI_SUCCESS);
 173 }
 174 
 175 int
 176 _init(void)
 177 {
 178         int error;
 179 
 180         error = mod_install(&modlinkage);
 181         return (error);
 182 }
 183 
 184 int
 185 _fini(void)
 186 {
 187         int error;
 188 
 189         error = mod_remove(&modlinkage);
 190         return (error);
 191 }
 192 
 193 int
 194 _info(struct modinfo *modinfop)
 195 {
 196         return (mod_info(&modlinkage, modinfop));
 197 }