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