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, NULL }
  89 };
  90 
  91 /*
  92  * cpunex_bus_ctl()
  93  *    This routine implements nexus bus ctl operations. Of importance are
  94  *    DDI_CTLOPS_REPORTDEV, DDI_CTLOPS_INITCHILD, DDI_CTLOPS_UNINITCHILD
  95  *    and DDI_CTLOPS_POWER. For DDI_CTLOPS_INITCHILD, it tries to lookup
  96  *    reg property on the child node and builds and sets the name.
  97  */
  98 static int
  99 cpunex_bus_ctl(dev_info_t *dip, dev_info_t *rdip, ddi_ctl_enum_t op, void *arg,
 100     void *result)
 101 {
 102         switch (op) {
 103                 case DDI_CTLOPS_REPORTDEV: {
 104                         dev_info_t *pdip = ddi_get_parent(rdip);
 105                         cmn_err(CE_CONT, "?%s%d at %s%d",
 106                             ddi_node_name(rdip), ddi_get_instance(rdip),
 107                             ddi_node_name(pdip), ddi_get_instance(pdip));
 108                         return (DDI_SUCCESS);
 109                 }
 110 
 111                 case DDI_CTLOPS_INITCHILD: {
 112                         dev_info_t *cdip = (dev_info_t *)arg;
 113                         int i;
 114                         char caddr[MAXNAMELEN];
 115 
 116                         i = ddi_prop_get_int(DDI_DEV_T_ANY, cdip,
 117                             DDI_PROP_DONTPASS, "reg", -1);
 118 
 119                         if (i == -1) {
 120                                 cmn_err(CE_NOTE, "!%s(%d): \"reg\" property "
 121                                     "not found", ddi_node_name(cdip),
 122                                     ddi_get_instance(cdip));
 123                                 return (DDI_NOT_WELL_FORMED);
 124                         }
 125 
 126                         (void) sprintf(caddr, "%d", i);
 127                         ddi_set_name_addr(cdip, caddr);
 128 
 129                         return (DDI_SUCCESS);
 130                 }
 131 
 132                 case DDI_CTLOPS_UNINITCHILD: {
 133                         ddi_prop_remove_all((dev_info_t *)arg);
 134                         ddi_set_name_addr((dev_info_t *)arg, NULL);
 135                         return (DDI_SUCCESS);
 136                 }
 137 
 138                 default: {
 139                         return (ddi_ctlops(dip, rdip, op, arg, result));
 140                 }
 141         }
 142 }
 143 
 144 /*ARGSUSED*/
 145 static int
 146 cpunex_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
 147 {
 148         switch (cmd) {
 149         case DDI_ATTACH:
 150         case DDI_RESUME:
 151                 break;
 152         default:
 153                 return (DDI_FAILURE);
 154         }
 155 
 156         return (DDI_SUCCESS);
 157 }
 158 
 159 /*ARGSUSED*/
 160 static int
 161 cpunex_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
 162 {
 163         switch (cmd) {
 164         case DDI_DETACH:
 165         case DDI_SUSPEND:
 166                 break;
 167         default:
 168                 return (DDI_FAILURE);
 169         }
 170 
 171         return (DDI_SUCCESS);
 172 }
 173 
 174 int
 175 _init(void)
 176 {
 177         int error;
 178 
 179         error = mod_install(&modlinkage);
 180         return (error);
 181 }
 182 
 183 int
 184 _fini(void)
 185 {
 186         int error;
 187 
 188         error = mod_remove(&modlinkage);
 189         return (error);
 190 }
 191 
 192 int
 193 _info(struct modinfo *modinfop)
 194 {
 195         return (mod_info(&modlinkage, modinfop));
 196 }