xref: /illumos-gate/usr/src/uts/i86pc/io/fipe/fipe_drv.c (revision eca2601c)
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
fipe_open(dev_t * devp,int flag,int otyp,cred_t * credp)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
fipe_close(dev_t dev,int flag,int otyp,cred_t * credp)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
fipe_ioctl(dev_t dev,int cmd,intptr_t arg,int mode,cred_t * credp,int * rvalp)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
fipe_getinfo(dev_info_t * dip,ddi_info_cmd_t infocmd,void * arg,void ** result)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
fipe_validate_dip(dev_info_t * dip)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
fipe_attach(dev_info_t * dip,ddi_attach_cmd_t cmd)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
fipe_detach(dev_info_t * dip,ddi_detach_cmd_t cmd)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
fipe_quiesce(dev_info_t * dip)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
_init(void)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
_info(struct modinfo * modinfop)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
_fini(void)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