1*eca2601cSRandy Fishel /* 2*eca2601cSRandy Fishel * CDDL HEADER START 3*eca2601cSRandy Fishel * 4*eca2601cSRandy Fishel * The contents of this file are subject to the terms of the 5*eca2601cSRandy Fishel * Common Development and Distribution License (the "License"). 6*eca2601cSRandy Fishel * You may not use this file except in compliance with the License. 7*eca2601cSRandy Fishel * 8*eca2601cSRandy Fishel * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9*eca2601cSRandy Fishel * or http://www.opensolaris.org/os/licensing. 10*eca2601cSRandy Fishel * See the License for the specific language governing permissions 11*eca2601cSRandy Fishel * and limitations under the License. 12*eca2601cSRandy Fishel * 13*eca2601cSRandy Fishel * When distributing Covered Code, include this CDDL HEADER in each 14*eca2601cSRandy Fishel * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15*eca2601cSRandy Fishel * If applicable, add the following below this CDDL HEADER, with the 16*eca2601cSRandy Fishel * fields enclosed by brackets "[]" replaced with your own identifying 17*eca2601cSRandy Fishel * information: Portions Copyright [yyyy] [name of copyright owner] 18*eca2601cSRandy Fishel * 19*eca2601cSRandy Fishel * CDDL HEADER END 20*eca2601cSRandy Fishel */ 21*eca2601cSRandy Fishel /* 22*eca2601cSRandy Fishel * Copyright (c) 2009, Intel Corporation. 23*eca2601cSRandy Fishel * All rights reserved. 24*eca2601cSRandy Fishel */ 25*eca2601cSRandy Fishel 26*eca2601cSRandy Fishel #include <sys/conf.h> 27*eca2601cSRandy Fishel #include <sys/cmn_err.h> 28*eca2601cSRandy Fishel #include <sys/ddi.h> 29*eca2601cSRandy Fishel #include <sys/file.h> 30*eca2601cSRandy Fishel #include <sys/modctl.h> 31*eca2601cSRandy Fishel #include <sys/pci.h> 32*eca2601cSRandy Fishel #include <sys/policy.h> 33*eca2601cSRandy Fishel #include <sys/stat.h> 34*eca2601cSRandy Fishel #include <sys/sunddi.h> 35*eca2601cSRandy Fishel #include <sys/synch.h> 36*eca2601cSRandy Fishel #include <sys/fipe.h> 37*eca2601cSRandy Fishel 38*eca2601cSRandy Fishel /* Configurable through /etc/system. */ 39*eca2601cSRandy Fishel int fipe_allow_attach = 1; 40*eca2601cSRandy Fishel int fipe_allow_detach = 1; 41*eca2601cSRandy Fishel 42*eca2601cSRandy Fishel static kmutex_t fipe_drv_lock; 43*eca2601cSRandy Fishel static dev_info_t *fipe_drv_dip; 44*eca2601cSRandy Fishel 45*eca2601cSRandy Fishel /* 46*eca2601cSRandy Fishel * PCI device ID for supported hardware. 47*eca2601cSRandy Fishel * For memory controller devices in Intel 5000/7300 series chipset, PCI vendor 48*eca2601cSRandy Fishel * id and PCI device id is read only, PCI subvendor id and PCI subsystem id is 49*eca2601cSRandy Fishel * write-once. So we could only rely on PCI vendor id and PCI device id here. 50*eca2601cSRandy Fishel * For all PCI functions (0,1,2,3) in device 0x10 on bus 0, they will have the 51*eca2601cSRandy Fishel * same PCI (vendor_id, device_id, subvendor_id, subsystem_id, class_id). 52*eca2601cSRandy Fishel * We only need to access PCI device (0, 0x10, 1), all other PCI functions will 53*eca2601cSRandy Fishel * be filtered out by unit address. 54*eca2601cSRandy Fishel */ 55*eca2601cSRandy Fishel static struct fipe_pci_id { 56*eca2601cSRandy Fishel uint16_t venid; 57*eca2601cSRandy Fishel uint16_t devid; 58*eca2601cSRandy Fishel uint16_t subvenid; 59*eca2601cSRandy Fishel uint16_t subsysid; 60*eca2601cSRandy Fishel char *unitaddr; 61*eca2601cSRandy Fishel } fipe_mc_pciids[] = { 62*eca2601cSRandy Fishel { 0x8086, 0x25f0, 0xffff, 0xffff, "10,1" }, /* Intel 5000P/V/X/Z */ 63*eca2601cSRandy Fishel { 0x8086, 0x360c, 0xffff, 0xffff, "10,1" } /* Intel 7300 NB */ 64*eca2601cSRandy Fishel }; 65*eca2601cSRandy Fishel 66*eca2601cSRandy Fishel /*ARGSUSED*/ 67*eca2601cSRandy Fishel static int 68*eca2601cSRandy Fishel fipe_open(dev_t *devp, int flag, int otyp, cred_t *credp) 69*eca2601cSRandy Fishel { 70*eca2601cSRandy Fishel if (otyp != OTYP_CHR) { 71*eca2601cSRandy Fishel cmn_err(CE_NOTE, "!fipe: invalid otyp %d in open.", otyp); 72*eca2601cSRandy Fishel return (EINVAL); 73*eca2601cSRandy Fishel } 74*eca2601cSRandy Fishel 75*eca2601cSRandy Fishel return (0); 76*eca2601cSRandy Fishel } 77*eca2601cSRandy Fishel 78*eca2601cSRandy Fishel /*ARGSUSED*/ 79*eca2601cSRandy Fishel static int 80*eca2601cSRandy Fishel fipe_close(dev_t dev, int flag, int otyp, cred_t *credp) 81*eca2601cSRandy Fishel { 82*eca2601cSRandy Fishel return (0); 83*eca2601cSRandy Fishel } 84*eca2601cSRandy Fishel 85*eca2601cSRandy Fishel /*ARGSUSED*/ 86*eca2601cSRandy Fishel static int 87*eca2601cSRandy Fishel fipe_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *credp, 88*eca2601cSRandy Fishel int *rvalp) 89*eca2601cSRandy Fishel { 90*eca2601cSRandy Fishel int rc = 0; 91*eca2601cSRandy Fishel fipe_pm_policy_t policy; 92*eca2601cSRandy Fishel 93*eca2601cSRandy Fishel /* First check permission. */ 94*eca2601cSRandy Fishel if (secpolicy_power_mgmt(credp) != 0) { 95*eca2601cSRandy Fishel return (EPERM); 96*eca2601cSRandy Fishel } 97*eca2601cSRandy Fishel 98*eca2601cSRandy Fishel switch (cmd) { 99*eca2601cSRandy Fishel case FIPE_IOCTL_START: 100*eca2601cSRandy Fishel if ((mode & FWRITE) == 0) { 101*eca2601cSRandy Fishel rc = EBADF; 102*eca2601cSRandy Fishel } else { 103*eca2601cSRandy Fishel mutex_enter(&fipe_drv_lock); 104*eca2601cSRandy Fishel rc = fipe_start(); 105*eca2601cSRandy Fishel mutex_exit(&fipe_drv_lock); 106*eca2601cSRandy Fishel rc = (rc == 0) ? 0 : ENXIO; 107*eca2601cSRandy Fishel } 108*eca2601cSRandy Fishel break; 109*eca2601cSRandy Fishel 110*eca2601cSRandy Fishel case FIPE_IOCTL_STOP: 111*eca2601cSRandy Fishel if ((mode & FWRITE) == 0) { 112*eca2601cSRandy Fishel rc = EBADF; 113*eca2601cSRandy Fishel } else { 114*eca2601cSRandy Fishel mutex_enter(&fipe_drv_lock); 115*eca2601cSRandy Fishel rc = fipe_stop(); 116*eca2601cSRandy Fishel mutex_exit(&fipe_drv_lock); 117*eca2601cSRandy Fishel rc = (rc == 0) ? 0 : ENXIO; 118*eca2601cSRandy Fishel } 119*eca2601cSRandy Fishel break; 120*eca2601cSRandy Fishel 121*eca2601cSRandy Fishel case FIPE_IOCTL_GET_PMPOLICY: 122*eca2601cSRandy Fishel if ((mode & FREAD) == 0) { 123*eca2601cSRandy Fishel rc = EBADF; 124*eca2601cSRandy Fishel } else { 125*eca2601cSRandy Fishel mutex_enter(&fipe_drv_lock); 126*eca2601cSRandy Fishel policy = fipe_get_pmpolicy(); 127*eca2601cSRandy Fishel mutex_exit(&fipe_drv_lock); 128*eca2601cSRandy Fishel rc = ddi_copyout(&policy, (void *)arg, 129*eca2601cSRandy Fishel sizeof (policy), mode); 130*eca2601cSRandy Fishel rc = (rc >= 0) ? 0 : EFAULT; 131*eca2601cSRandy Fishel } 132*eca2601cSRandy Fishel break; 133*eca2601cSRandy Fishel 134*eca2601cSRandy Fishel case FIPE_IOCTL_SET_PMPOLICY: 135*eca2601cSRandy Fishel if ((mode & FWRITE) == 0) { 136*eca2601cSRandy Fishel rc = EBADF; 137*eca2601cSRandy Fishel } else { 138*eca2601cSRandy Fishel mutex_enter(&fipe_drv_lock); 139*eca2601cSRandy Fishel rc = fipe_set_pmpolicy((fipe_pm_policy_t)arg); 140*eca2601cSRandy Fishel mutex_exit(&fipe_drv_lock); 141*eca2601cSRandy Fishel rc = (rc == 0) ? 0 : ENXIO; 142*eca2601cSRandy Fishel } 143*eca2601cSRandy Fishel break; 144*eca2601cSRandy Fishel 145*eca2601cSRandy Fishel default: 146*eca2601cSRandy Fishel cmn_err(CE_NOTE, "!fipe: unknown ioctl command %d.", cmd); 147*eca2601cSRandy Fishel rc = ENOTSUP; 148*eca2601cSRandy Fishel break; 149*eca2601cSRandy Fishel } 150*eca2601cSRandy Fishel 151*eca2601cSRandy Fishel return (rc); 152*eca2601cSRandy Fishel } 153*eca2601cSRandy Fishel 154*eca2601cSRandy Fishel /*ARGSUSED*/ 155*eca2601cSRandy Fishel static int 156*eca2601cSRandy Fishel fipe_getinfo(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result) 157*eca2601cSRandy Fishel { 158*eca2601cSRandy Fishel switch (infocmd) { 159*eca2601cSRandy Fishel case DDI_INFO_DEVT2DEVINFO: 160*eca2601cSRandy Fishel if (fipe_drv_dip != NULL) { 161*eca2601cSRandy Fishel *result = fipe_drv_dip; 162*eca2601cSRandy Fishel return (DDI_SUCCESS); 163*eca2601cSRandy Fishel } else { 164*eca2601cSRandy Fishel *result = NULL; 165*eca2601cSRandy Fishel return (DDI_FAILURE); 166*eca2601cSRandy Fishel } 167*eca2601cSRandy Fishel 168*eca2601cSRandy Fishel case DDI_INFO_DEVT2INSTANCE: 169*eca2601cSRandy Fishel if (fipe_drv_dip != NULL) { 170*eca2601cSRandy Fishel *result = (void *)(uintptr_t) 171*eca2601cSRandy Fishel ddi_get_instance(fipe_drv_dip); 172*eca2601cSRandy Fishel return (DDI_SUCCESS); 173*eca2601cSRandy Fishel } else { 174*eca2601cSRandy Fishel *result = NULL; 175*eca2601cSRandy Fishel return (DDI_FAILURE); 176*eca2601cSRandy Fishel } 177*eca2601cSRandy Fishel 178*eca2601cSRandy Fishel default: 179*eca2601cSRandy Fishel *result = NULL; 180*eca2601cSRandy Fishel return (DDI_FAILURE); 181*eca2601cSRandy Fishel } 182*eca2601cSRandy Fishel } 183*eca2601cSRandy Fishel 184*eca2601cSRandy Fishel /* Validate whether it's supported hardware. */ 185*eca2601cSRandy Fishel static int 186*eca2601cSRandy Fishel fipe_validate_dip(dev_info_t *dip) 187*eca2601cSRandy Fishel { 188*eca2601cSRandy Fishel int i, rc = -1; 189*eca2601cSRandy Fishel char *unitaddr; 190*eca2601cSRandy Fishel struct fipe_pci_id *ip; 191*eca2601cSRandy Fishel ddi_acc_handle_t handle; 192*eca2601cSRandy Fishel uint16_t venid, devid, subvenid, subsysid; 193*eca2601cSRandy Fishel 194*eca2601cSRandy Fishel /* Get device unit address, it's "devid,funcid" in hexadecimal. */ 195*eca2601cSRandy Fishel if (ddi_prop_lookup_string(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, 196*eca2601cSRandy Fishel "unit-address", &unitaddr) != DDI_PROP_SUCCESS) { 197*eca2601cSRandy Fishel cmn_err(CE_CONT, "?fipe: failed to get deivce unit address."); 198*eca2601cSRandy Fishel return (-1); 199*eca2601cSRandy Fishel } 200*eca2601cSRandy Fishel if (pci_config_setup(dip, &handle) != DDI_SUCCESS) { 201*eca2601cSRandy Fishel cmn_err(CE_CONT, "?fipe: failed to setup pcicfg handler."); 202*eca2601cSRandy Fishel ddi_prop_free(unitaddr); 203*eca2601cSRandy Fishel return (-1); 204*eca2601cSRandy Fishel } 205*eca2601cSRandy Fishel venid = pci_config_get16(handle, PCI_CONF_VENID); 206*eca2601cSRandy Fishel devid = pci_config_get16(handle, PCI_CONF_DEVID); 207*eca2601cSRandy Fishel subvenid = pci_config_get16(handle, PCI_CONF_SUBVENID); 208*eca2601cSRandy Fishel subsysid = pci_config_get16(handle, PCI_CONF_SUBSYSID); 209*eca2601cSRandy Fishel 210*eca2601cSRandy Fishel /* Validate device. */ 211*eca2601cSRandy Fishel for (rc = -1, i = 0, ip = &fipe_mc_pciids[0]; 212*eca2601cSRandy Fishel i < sizeof (fipe_mc_pciids) / sizeof (fipe_mc_pciids[0]); 213*eca2601cSRandy Fishel i++, ip++) { 214*eca2601cSRandy Fishel if ((ip->venid == 0xffffu || ip->venid == venid) && 215*eca2601cSRandy Fishel (ip->devid == 0xffffu || ip->devid == devid) && 216*eca2601cSRandy Fishel (ip->subvenid == 0xffffu || ip->subvenid == subvenid) && 217*eca2601cSRandy Fishel (ip->subsysid == 0xffffu || ip->subsysid == subsysid) && 218*eca2601cSRandy Fishel (ip->unitaddr == NULL || 219*eca2601cSRandy Fishel strcmp(ip->unitaddr, unitaddr) == 0)) { 220*eca2601cSRandy Fishel rc = 0; 221*eca2601cSRandy Fishel break; 222*eca2601cSRandy Fishel } 223*eca2601cSRandy Fishel } 224*eca2601cSRandy Fishel 225*eca2601cSRandy Fishel pci_config_teardown(&handle); 226*eca2601cSRandy Fishel ddi_prop_free(unitaddr); 227*eca2601cSRandy Fishel 228*eca2601cSRandy Fishel return (rc); 229*eca2601cSRandy Fishel } 230*eca2601cSRandy Fishel 231*eca2601cSRandy Fishel static int 232*eca2601cSRandy Fishel fipe_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 233*eca2601cSRandy Fishel { 234*eca2601cSRandy Fishel char *ptr; 235*eca2601cSRandy Fishel int ignore = 0, rc = DDI_FAILURE; 236*eca2601cSRandy Fishel 237*eca2601cSRandy Fishel mutex_enter(&fipe_drv_lock); 238*eca2601cSRandy Fishel switch (cmd) { 239*eca2601cSRandy Fishel case DDI_ATTACH: 240*eca2601cSRandy Fishel /* Check whether it has been disabled by user. */ 241*eca2601cSRandy Fishel if (ddi_prop_lookup_string(DDI_DEV_T_ANY, dip, 0, 242*eca2601cSRandy Fishel "disable_fipe_pm", &ptr) == DDI_SUCCESS) { 243*eca2601cSRandy Fishel if (strcasecmp(ptr, "true") == 0 || 244*eca2601cSRandy Fishel strcasecmp(ptr, "yes") == 0) { 245*eca2601cSRandy Fishel fipe_allow_attach = 0; 246*eca2601cSRandy Fishel } 247*eca2601cSRandy Fishel ddi_prop_free(ptr); 248*eca2601cSRandy Fishel } 249*eca2601cSRandy Fishel if (fipe_allow_attach == 0) { 250*eca2601cSRandy Fishel cmn_err(CE_WARN, 251*eca2601cSRandy Fishel "fipe: driver has been disabled by user."); 252*eca2601cSRandy Fishel ignore = 1; 253*eca2601cSRandy Fishel break; 254*eca2601cSRandy Fishel } 255*eca2601cSRandy Fishel 256*eca2601cSRandy Fishel /* Filter out unwanted PCI functions. */ 257*eca2601cSRandy Fishel if ((ignore = fipe_validate_dip(dip)) != 0) { 258*eca2601cSRandy Fishel break; 259*eca2601cSRandy Fishel /* There should be only one MC device in system. */ 260*eca2601cSRandy Fishel } else if (fipe_drv_dip != NULL) { 261*eca2601cSRandy Fishel cmn_err(CE_NOTE, 262*eca2601cSRandy Fishel "!fipe: more than one hardware instances found."); 263*eca2601cSRandy Fishel break; 264*eca2601cSRandy Fishel } 265*eca2601cSRandy Fishel fipe_drv_dip = dip; 266*eca2601cSRandy Fishel 267*eca2601cSRandy Fishel /* Initialize and start power management subsystem. */ 268*eca2601cSRandy Fishel if (fipe_init(fipe_drv_dip) != 0) { 269*eca2601cSRandy Fishel fipe_drv_dip = NULL; 270*eca2601cSRandy Fishel break; 271*eca2601cSRandy Fishel } else if (fipe_start() != 0) { 272*eca2601cSRandy Fishel (void) fipe_fini(); 273*eca2601cSRandy Fishel fipe_drv_dip = NULL; 274*eca2601cSRandy Fishel break; 275*eca2601cSRandy Fishel } 276*eca2601cSRandy Fishel 277*eca2601cSRandy Fishel /* Ignore error from creating minor node. */ 278*eca2601cSRandy Fishel if (ddi_create_minor_node(dip, "fipe", S_IFCHR, 0, 279*eca2601cSRandy Fishel "ddi_mem_pm", 0) != DDI_SUCCESS) { 280*eca2601cSRandy Fishel cmn_err(CE_CONT, 281*eca2601cSRandy Fishel "?fipe: failed to create device minor node.\n"); 282*eca2601cSRandy Fishel } 283*eca2601cSRandy Fishel 284*eca2601cSRandy Fishel rc = DDI_SUCCESS; 285*eca2601cSRandy Fishel break; 286*eca2601cSRandy Fishel 287*eca2601cSRandy Fishel case DDI_RESUME: 288*eca2601cSRandy Fishel if (fipe_resume() == 0) { 289*eca2601cSRandy Fishel rc = DDI_SUCCESS; 290*eca2601cSRandy Fishel } 291*eca2601cSRandy Fishel break; 292*eca2601cSRandy Fishel 293*eca2601cSRandy Fishel default: 294*eca2601cSRandy Fishel break; 295*eca2601cSRandy Fishel } 296*eca2601cSRandy Fishel mutex_exit(&fipe_drv_lock); 297*eca2601cSRandy Fishel 298*eca2601cSRandy Fishel if (ignore == 0 && rc != DDI_SUCCESS) { 299*eca2601cSRandy Fishel cmn_err(CE_NOTE, "!fipe: failed to attach or resume device."); 300*eca2601cSRandy Fishel } 301*eca2601cSRandy Fishel 302*eca2601cSRandy Fishel return (rc); 303*eca2601cSRandy Fishel } 304*eca2601cSRandy Fishel 305*eca2601cSRandy Fishel /*ARGSUSED*/ 306*eca2601cSRandy Fishel static int 307*eca2601cSRandy Fishel fipe_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 308*eca2601cSRandy Fishel { 309*eca2601cSRandy Fishel int rc = DDI_FAILURE; 310*eca2601cSRandy Fishel 311*eca2601cSRandy Fishel mutex_enter(&fipe_drv_lock); 312*eca2601cSRandy Fishel switch (cmd) { 313*eca2601cSRandy Fishel case DDI_DETACH: 314*eca2601cSRandy Fishel if (fipe_allow_detach == 0 || dip != fipe_drv_dip) { 315*eca2601cSRandy Fishel break; 316*eca2601cSRandy Fishel } 317*eca2601cSRandy Fishel if (fipe_stop() != 0) { 318*eca2601cSRandy Fishel break; 319*eca2601cSRandy Fishel } else if (fipe_fini() != 0) { 320*eca2601cSRandy Fishel (void) fipe_start(); 321*eca2601cSRandy Fishel break; 322*eca2601cSRandy Fishel } 323*eca2601cSRandy Fishel ddi_remove_minor_node(dip, NULL); 324*eca2601cSRandy Fishel fipe_drv_dip = NULL; 325*eca2601cSRandy Fishel rc = DDI_SUCCESS; 326*eca2601cSRandy Fishel break; 327*eca2601cSRandy Fishel 328*eca2601cSRandy Fishel case DDI_SUSPEND: 329*eca2601cSRandy Fishel if (fipe_suspend() == 0) { 330*eca2601cSRandy Fishel rc = DDI_SUCCESS; 331*eca2601cSRandy Fishel } 332*eca2601cSRandy Fishel break; 333*eca2601cSRandy Fishel 334*eca2601cSRandy Fishel default: 335*eca2601cSRandy Fishel break; 336*eca2601cSRandy Fishel } 337*eca2601cSRandy Fishel mutex_exit(&fipe_drv_lock); 338*eca2601cSRandy Fishel 339*eca2601cSRandy Fishel if (rc != DDI_SUCCESS) { 340*eca2601cSRandy Fishel cmn_err(CE_NOTE, "!fipe: failed to detach or suspend device."); 341*eca2601cSRandy Fishel } 342*eca2601cSRandy Fishel 343*eca2601cSRandy Fishel return (rc); 344*eca2601cSRandy Fishel } 345*eca2601cSRandy Fishel 346*eca2601cSRandy Fishel static int 347*eca2601cSRandy Fishel fipe_quiesce(dev_info_t *dip) 348*eca2601cSRandy Fishel { 349*eca2601cSRandy Fishel if (dip != fipe_drv_dip) { 350*eca2601cSRandy Fishel return (DDI_SUCCESS); 351*eca2601cSRandy Fishel } 352*eca2601cSRandy Fishel /* Quiesce hardware by stopping power management subsystem. */ 353*eca2601cSRandy Fishel if (fipe_suspend() != 0) { 354*eca2601cSRandy Fishel cmn_err(CE_NOTE, "!fipe: failed to quiesce device."); 355*eca2601cSRandy Fishel return (DDI_FAILURE); 356*eca2601cSRandy Fishel } 357*eca2601cSRandy Fishel 358*eca2601cSRandy Fishel return (DDI_SUCCESS); 359*eca2601cSRandy Fishel } 360*eca2601cSRandy Fishel 361*eca2601cSRandy Fishel static struct cb_ops fipe_cb_ops = { 362*eca2601cSRandy Fishel fipe_open, 363*eca2601cSRandy Fishel fipe_close, 364*eca2601cSRandy Fishel nodev, /* not a block driver */ 365*eca2601cSRandy Fishel nodev, /* no print routine */ 366*eca2601cSRandy Fishel nodev, /* no dump routine */ 367*eca2601cSRandy Fishel nodev, /* no read routine */ 368*eca2601cSRandy Fishel nodev, /* no write routine */ 369*eca2601cSRandy Fishel fipe_ioctl, 370*eca2601cSRandy Fishel nodev, /* no devmap routine */ 371*eca2601cSRandy Fishel nodev, /* no mmap routine */ 372*eca2601cSRandy Fishel nodev, /* no segmap routine */ 373*eca2601cSRandy Fishel nochpoll, /* no chpoll routine */ 374*eca2601cSRandy Fishel ddi_prop_op, 375*eca2601cSRandy Fishel 0, /* not a STREAMS driver */ 376*eca2601cSRandy Fishel D_NEW | D_MP, /* safe for multi-thread/multi-processor */ 377*eca2601cSRandy Fishel }; 378*eca2601cSRandy Fishel 379*eca2601cSRandy Fishel static struct dev_ops fipe_ops = { 380*eca2601cSRandy Fishel DEVO_REV, /* devo_rev */ 381*eca2601cSRandy Fishel 0, /* devo_refcnt */ 382*eca2601cSRandy Fishel fipe_getinfo, /* devo_getinfo */ 383*eca2601cSRandy Fishel nulldev, /* devo_identify */ 384*eca2601cSRandy Fishel nulldev, /* devo_probe */ 385*eca2601cSRandy Fishel fipe_attach, /* devo_attach */ 386*eca2601cSRandy Fishel fipe_detach, /* devo_detach */ 387*eca2601cSRandy Fishel nodev, /* devo_reset */ 388*eca2601cSRandy Fishel &fipe_cb_ops, /* devo_cb_ops */ 389*eca2601cSRandy Fishel NULL, /* devo_bus_ops */ 390*eca2601cSRandy Fishel NULL, /* devo_power */ 391*eca2601cSRandy Fishel &fipe_quiesce, /* devo_quiesce */ 392*eca2601cSRandy Fishel }; 393*eca2601cSRandy Fishel 394*eca2601cSRandy Fishel static struct modldrv modldrv = { 395*eca2601cSRandy Fishel &mod_driverops, 396*eca2601cSRandy Fishel "Intel 5000/7300 memory controller driver", 397*eca2601cSRandy Fishel &fipe_ops 398*eca2601cSRandy Fishel }; 399*eca2601cSRandy Fishel 400*eca2601cSRandy Fishel static struct modlinkage modlinkage = { 401*eca2601cSRandy Fishel MODREV_1, 402*eca2601cSRandy Fishel (void *)&modldrv, 403*eca2601cSRandy Fishel NULL 404*eca2601cSRandy Fishel }; 405*eca2601cSRandy Fishel 406*eca2601cSRandy Fishel int 407*eca2601cSRandy Fishel _init(void) 408*eca2601cSRandy Fishel { 409*eca2601cSRandy Fishel fipe_drv_dip = NULL; 410*eca2601cSRandy Fishel mutex_init(&fipe_drv_lock, NULL, MUTEX_DRIVER, NULL); 411*eca2601cSRandy Fishel 412*eca2601cSRandy Fishel return (mod_install(&modlinkage)); 413*eca2601cSRandy Fishel } 414*eca2601cSRandy Fishel 415*eca2601cSRandy Fishel int 416*eca2601cSRandy Fishel _info(struct modinfo *modinfop) 417*eca2601cSRandy Fishel { 418*eca2601cSRandy Fishel return (mod_info(&modlinkage, modinfop)); 419*eca2601cSRandy Fishel } 420*eca2601cSRandy Fishel 421*eca2601cSRandy Fishel int 422*eca2601cSRandy Fishel _fini(void) 423*eca2601cSRandy Fishel { 424*eca2601cSRandy Fishel int err; 425*eca2601cSRandy Fishel 426*eca2601cSRandy Fishel if ((err = mod_remove(&modlinkage)) == 0) { 427*eca2601cSRandy Fishel mutex_destroy(&fipe_drv_lock); 428*eca2601cSRandy Fishel fipe_drv_dip = NULL; 429*eca2601cSRandy Fishel } 430*eca2601cSRandy Fishel 431*eca2601cSRandy Fishel return (err); 432*eca2601cSRandy Fishel } 433