xref: /onnv-gate/usr/src/uts/i86pc/io/ioat/ioat.c (revision 6707:c3bc7e4da11b)
1*6707Sbrutus /*
2*6707Sbrutus  * CDDL HEADER START
3*6707Sbrutus  *
4*6707Sbrutus  * The contents of this file are subject to the terms of the
5*6707Sbrutus  * Common Development and Distribution License (the "License").
6*6707Sbrutus  * You may not use this file except in compliance with the License.
7*6707Sbrutus  *
8*6707Sbrutus  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*6707Sbrutus  * or http://www.opensolaris.org/os/licensing.
10*6707Sbrutus  * See the License for the specific language governing permissions
11*6707Sbrutus  * and limitations under the License.
12*6707Sbrutus  *
13*6707Sbrutus  * When distributing Covered Code, include this CDDL HEADER in each
14*6707Sbrutus  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*6707Sbrutus  * If applicable, add the following below this CDDL HEADER, with the
16*6707Sbrutus  * fields enclosed by brackets "[]" replaced with your own identifying
17*6707Sbrutus  * information: Portions Copyright [yyyy] [name of copyright owner]
18*6707Sbrutus  *
19*6707Sbrutus  * CDDL HEADER END
20*6707Sbrutus  */
21*6707Sbrutus 
22*6707Sbrutus /*
23*6707Sbrutus  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
24*6707Sbrutus  * Use is subject to license terms.
25*6707Sbrutus  */
26*6707Sbrutus 
27*6707Sbrutus #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*6707Sbrutus 
29*6707Sbrutus #include <sys/errno.h>
30*6707Sbrutus #include <sys/types.h>
31*6707Sbrutus #include <sys/conf.h>
32*6707Sbrutus #include <sys/kmem.h>
33*6707Sbrutus #include <sys/ddi.h>
34*6707Sbrutus #include <sys/stat.h>
35*6707Sbrutus #include <sys/sunddi.h>
36*6707Sbrutus #include <sys/file.h>
37*6707Sbrutus #include <sys/open.h>
38*6707Sbrutus #include <sys/modctl.h>
39*6707Sbrutus #include <sys/ddi_impldefs.h>
40*6707Sbrutus #include <sys/sysmacros.h>
41*6707Sbrutus 
42*6707Sbrutus #include <sys/ioat.h>
43*6707Sbrutus 
44*6707Sbrutus static int ioat_open(dev_t *devp, int flag, int otyp, cred_t *cred);
45*6707Sbrutus static int ioat_close(dev_t devp, int flag, int otyp, cred_t *cred);
46*6707Sbrutus static int ioat_attach(dev_info_t *devi, ddi_attach_cmd_t cmd);
47*6707Sbrutus static int ioat_detach(dev_info_t *devi, ddi_detach_cmd_t cmd);
48*6707Sbrutus static int ioat_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg,
49*6707Sbrutus     void **result);
50*6707Sbrutus 
51*6707Sbrutus static 	struct cb_ops ioat_cb_ops = {
52*6707Sbrutus 	ioat_open,		/* cb_open */
53*6707Sbrutus 	ioat_close,		/* cb_close */
54*6707Sbrutus 	nodev,			/* cb_strategy */
55*6707Sbrutus 	nodev,			/* cb_print */
56*6707Sbrutus 	nodev,			/* cb_dump */
57*6707Sbrutus 	nodev,			/* cb_read */
58*6707Sbrutus 	nodev,			/* cb_write */
59*6707Sbrutus 	ioat_ioctl,		/* cb_ioctl */
60*6707Sbrutus 	nodev,			/* cb_devmap */
61*6707Sbrutus 	nodev,			/* cb_mmap */
62*6707Sbrutus 	nodev,			/* cb_segmap */
63*6707Sbrutus 	nochpoll,		/* cb_chpoll */
64*6707Sbrutus 	ddi_prop_op,		/* cb_prop_op */
65*6707Sbrutus 	NULL,			/* cb_stream */
66*6707Sbrutus 	D_NEW | D_MP | D_64BIT | D_DEVMAP,	/* cb_flag */
67*6707Sbrutus 	CB_REV
68*6707Sbrutus };
69*6707Sbrutus 
70*6707Sbrutus static struct dev_ops ioat_dev_ops = {
71*6707Sbrutus 	DEVO_REV,		/* devo_rev */
72*6707Sbrutus 	0,			/* devo_refcnt */
73*6707Sbrutus 	ioat_getinfo,		/* devo_getinfo */
74*6707Sbrutus 	nulldev,		/* devo_identify */
75*6707Sbrutus 	nulldev,		/* devo_probe */
76*6707Sbrutus 	ioat_attach,		/* devo_attach */
77*6707Sbrutus 	ioat_detach,		/* devo_detach */
78*6707Sbrutus 	nodev,			/* devo_reset */
79*6707Sbrutus 	&ioat_cb_ops,		/* devo_cb_ops */
80*6707Sbrutus 	NULL,			/* devo_bus_ops */
81*6707Sbrutus 	NULL			/* power */
82*6707Sbrutus };
83*6707Sbrutus 
84*6707Sbrutus static struct modldrv ioat_modldrv = {
85*6707Sbrutus 	&mod_driverops,		/* Type of module.  This one is a driver */
86*6707Sbrutus 	"ioat driver v%I%",	/* Name of the module. */
87*6707Sbrutus 	&ioat_dev_ops,		/* driver ops */
88*6707Sbrutus };
89*6707Sbrutus 
90*6707Sbrutus static struct modlinkage ioat_modlinkage = {
91*6707Sbrutus 	MODREV_1,
92*6707Sbrutus 	(void *) &ioat_modldrv,
93*6707Sbrutus 	NULL
94*6707Sbrutus };
95*6707Sbrutus 
96*6707Sbrutus 
97*6707Sbrutus void *ioat_statep;
98*6707Sbrutus 
99*6707Sbrutus static int ioat_chip_init(ioat_state_t *state);
100*6707Sbrutus static void ioat_chip_fini(ioat_state_t *state);
101*6707Sbrutus static int ioat_drv_init(ioat_state_t *state);
102*6707Sbrutus static void ioat_drv_fini(ioat_state_t *state);
103*6707Sbrutus static uint_t ioat_isr(caddr_t parm);
104*6707Sbrutus static void ioat_intr_enable(ioat_state_t *state);
105*6707Sbrutus static void ioat_intr_disable(ioat_state_t *state);
106*6707Sbrutus void ioat_detach_finish(ioat_state_t *state);
107*6707Sbrutus 
108*6707Sbrutus 
109*6707Sbrutus ddi_device_acc_attr_t ioat_acc_attr = {
110*6707Sbrutus 	DDI_DEVICE_ATTR_V0,		/* devacc_attr_version */
111*6707Sbrutus 	DDI_NEVERSWAP_ACC,		/* devacc_attr_endian_flags */
112*6707Sbrutus 	DDI_STORECACHING_OK_ACC,	/* devacc_attr_dataorder */
113*6707Sbrutus 	DDI_DEFAULT_ACC			/* devacc_attr_access */
114*6707Sbrutus };
115*6707Sbrutus 
116*6707Sbrutus /* dcopy callback interface */
117*6707Sbrutus dcopy_device_cb_t ioat_cb = {
118*6707Sbrutus 	DCOPY_DEVICECB_V0,
119*6707Sbrutus 	0,		/* reserved */
120*6707Sbrutus 	ioat_channel_alloc,
121*6707Sbrutus 	ioat_channel_free,
122*6707Sbrutus 	ioat_cmd_alloc,
123*6707Sbrutus 	ioat_cmd_free,
124*6707Sbrutus 	ioat_cmd_post,
125*6707Sbrutus 	ioat_cmd_poll,
126*6707Sbrutus 	ioat_unregister_complete
127*6707Sbrutus };
128*6707Sbrutus 
129*6707Sbrutus /*
130*6707Sbrutus  * _init()
131*6707Sbrutus  */
132*6707Sbrutus int
133*6707Sbrutus _init(void)
134*6707Sbrutus {
135*6707Sbrutus 	int e;
136*6707Sbrutus 
137*6707Sbrutus 	e = ddi_soft_state_init(&ioat_statep, sizeof (ioat_state_t), 1);
138*6707Sbrutus 	if (e != 0) {
139*6707Sbrutus 		return (e);
140*6707Sbrutus 	}
141*6707Sbrutus 
142*6707Sbrutus 	e = mod_install(&ioat_modlinkage);
143*6707Sbrutus 	if (e != 0) {
144*6707Sbrutus 		ddi_soft_state_fini(&ioat_statep);
145*6707Sbrutus 		return (e);
146*6707Sbrutus 	}
147*6707Sbrutus 
148*6707Sbrutus 	return (0);
149*6707Sbrutus }
150*6707Sbrutus 
151*6707Sbrutus /*
152*6707Sbrutus  * _info()
153*6707Sbrutus  */
154*6707Sbrutus int
155*6707Sbrutus _info(struct modinfo *modinfop)
156*6707Sbrutus {
157*6707Sbrutus 	return (mod_info(&ioat_modlinkage, modinfop));
158*6707Sbrutus }
159*6707Sbrutus 
160*6707Sbrutus /*
161*6707Sbrutus  * _fini()
162*6707Sbrutus  */
163*6707Sbrutus int
164*6707Sbrutus _fini(void)
165*6707Sbrutus {
166*6707Sbrutus 	int e;
167*6707Sbrutus 
168*6707Sbrutus 	e = mod_remove(&ioat_modlinkage);
169*6707Sbrutus 	if (e != 0) {
170*6707Sbrutus 		return (e);
171*6707Sbrutus 	}
172*6707Sbrutus 
173*6707Sbrutus 	ddi_soft_state_fini(&ioat_statep);
174*6707Sbrutus 
175*6707Sbrutus 	return (0);
176*6707Sbrutus }
177*6707Sbrutus 
178*6707Sbrutus /*
179*6707Sbrutus  * ioat_attach()
180*6707Sbrutus  */
181*6707Sbrutus static int
182*6707Sbrutus ioat_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
183*6707Sbrutus {
184*6707Sbrutus 	ioat_state_t *state;
185*6707Sbrutus 	int instance;
186*6707Sbrutus 	int e;
187*6707Sbrutus 
188*6707Sbrutus 
189*6707Sbrutus 	switch (cmd) {
190*6707Sbrutus 	case DDI_ATTACH:
191*6707Sbrutus 		break;
192*6707Sbrutus 
193*6707Sbrutus 	case DDI_RESUME:
194*6707Sbrutus 		instance = ddi_get_instance(dip);
195*6707Sbrutus 		state = ddi_get_soft_state(ioat_statep, instance);
196*6707Sbrutus 		if (state == NULL) {
197*6707Sbrutus 			return (DDI_FAILURE);
198*6707Sbrutus 		}
199*6707Sbrutus 		e = ioat_channel_resume(state);
200*6707Sbrutus 		if (e != DDI_SUCCESS) {
201*6707Sbrutus 			return (DDI_FAILURE);
202*6707Sbrutus 		}
203*6707Sbrutus 		ioat_intr_enable(state);
204*6707Sbrutus 		return (DDI_SUCCESS);
205*6707Sbrutus 
206*6707Sbrutus 	default:
207*6707Sbrutus 		return (DDI_FAILURE);
208*6707Sbrutus 	}
209*6707Sbrutus 
210*6707Sbrutus 	instance = ddi_get_instance(dip);
211*6707Sbrutus 	e = ddi_soft_state_zalloc(ioat_statep, instance);
212*6707Sbrutus 	if (e != DDI_SUCCESS) {
213*6707Sbrutus 		return (DDI_FAILURE);
214*6707Sbrutus 	}
215*6707Sbrutus 	state = ddi_get_soft_state(ioat_statep, instance);
216*6707Sbrutus 	if (state == NULL) {
217*6707Sbrutus 		goto attachfail_get_soft_state;
218*6707Sbrutus 	}
219*6707Sbrutus 
220*6707Sbrutus 	state->is_dip = dip;
221*6707Sbrutus 	state->is_instance = instance;
222*6707Sbrutus 
223*6707Sbrutus 	/* setup the registers, save away some device info */
224*6707Sbrutus 	e = ioat_chip_init(state);
225*6707Sbrutus 	if (e != DDI_SUCCESS) {
226*6707Sbrutus 		goto attachfail_chip_init;
227*6707Sbrutus 	}
228*6707Sbrutus 
229*6707Sbrutus 	/* initialize driver state, must be after chip init */
230*6707Sbrutus 	e = ioat_drv_init(state);
231*6707Sbrutus 	if (e != DDI_SUCCESS) {
232*6707Sbrutus 		goto attachfail_drv_init;
233*6707Sbrutus 	}
234*6707Sbrutus 
235*6707Sbrutus 	/* create the minor node (for the ioctl) */
236*6707Sbrutus 	e = ddi_create_minor_node(dip, "ioat", S_IFCHR, instance, DDI_PSEUDO,
237*6707Sbrutus 	    0);
238*6707Sbrutus 	if (e != DDI_SUCCESS) {
239*6707Sbrutus 		goto attachfail_minor_node;
240*6707Sbrutus 	}
241*6707Sbrutus 
242*6707Sbrutus 	/* Enable device interrupts */
243*6707Sbrutus 	ioat_intr_enable(state);
244*6707Sbrutus 
245*6707Sbrutus 	/* Report that driver was loaded */
246*6707Sbrutus 	ddi_report_dev(dip);
247*6707Sbrutus 
248*6707Sbrutus 	/* register with dcopy */
249*6707Sbrutus 	e = dcopy_device_register(state, &state->is_deviceinfo,
250*6707Sbrutus 	    &state->is_device_handle);
251*6707Sbrutus 	if (e != DCOPY_SUCCESS) {
252*6707Sbrutus 		goto attachfail_register;
253*6707Sbrutus 	}
254*6707Sbrutus 
255*6707Sbrutus 	return (DDI_SUCCESS);
256*6707Sbrutus 
257*6707Sbrutus attachfail_register:
258*6707Sbrutus 	ioat_intr_disable(state);
259*6707Sbrutus 	ddi_remove_minor_node(dip, NULL);
260*6707Sbrutus attachfail_minor_node:
261*6707Sbrutus 	ioat_drv_fini(state);
262*6707Sbrutus attachfail_drv_init:
263*6707Sbrutus 	ioat_chip_fini(state);
264*6707Sbrutus attachfail_chip_init:
265*6707Sbrutus attachfail_get_soft_state:
266*6707Sbrutus 	(void) ddi_soft_state_free(ioat_statep, instance);
267*6707Sbrutus 
268*6707Sbrutus 	return (DDI_FAILURE);
269*6707Sbrutus }
270*6707Sbrutus 
271*6707Sbrutus /*
272*6707Sbrutus  * ioat_detach()
273*6707Sbrutus  */
274*6707Sbrutus static int
275*6707Sbrutus ioat_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
276*6707Sbrutus {
277*6707Sbrutus 	ioat_state_t *state;
278*6707Sbrutus 	int instance;
279*6707Sbrutus 	int e;
280*6707Sbrutus 
281*6707Sbrutus 
282*6707Sbrutus 	instance = ddi_get_instance(dip);
283*6707Sbrutus 	state = ddi_get_soft_state(ioat_statep, instance);
284*6707Sbrutus 	if (state == NULL) {
285*6707Sbrutus 		return (DDI_FAILURE);
286*6707Sbrutus 	}
287*6707Sbrutus 
288*6707Sbrutus 	switch (cmd) {
289*6707Sbrutus 	case DDI_DETACH:
290*6707Sbrutus 		break;
291*6707Sbrutus 
292*6707Sbrutus 	case DDI_SUSPEND:
293*6707Sbrutus 		ioat_channel_suspend(state);
294*6707Sbrutus 		return (DDI_SUCCESS);
295*6707Sbrutus 
296*6707Sbrutus 	default:
297*6707Sbrutus 		return (DDI_FAILURE);
298*6707Sbrutus 	}
299*6707Sbrutus 
300*6707Sbrutus 	/*
301*6707Sbrutus 	 * try to unregister from dcopy.  Since this driver doesn't follow the
302*6707Sbrutus 	 * traditional parent/child model, we may still be in use so we can't
303*6707Sbrutus 	 * detach yet.
304*6707Sbrutus 	 */
305*6707Sbrutus 	e = dcopy_device_unregister(&state->is_device_handle);
306*6707Sbrutus 	if (e != DCOPY_SUCCESS) {
307*6707Sbrutus 		if (e == DCOPY_PENDING) {
308*6707Sbrutus 			cmn_err(CE_NOTE, "device busy, performing asynchronous"
309*6707Sbrutus 			    " detach\n");
310*6707Sbrutus 		}
311*6707Sbrutus 		return (DDI_FAILURE);
312*6707Sbrutus 	}
313*6707Sbrutus 
314*6707Sbrutus 	ioat_detach_finish(state);
315*6707Sbrutus 
316*6707Sbrutus 	return (DDI_SUCCESS);
317*6707Sbrutus }
318*6707Sbrutus 
319*6707Sbrutus /*
320*6707Sbrutus  * ioat_getinfo()
321*6707Sbrutus  */
322*6707Sbrutus /*ARGSUSED*/
323*6707Sbrutus static int
324*6707Sbrutus ioat_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **result)
325*6707Sbrutus {
326*6707Sbrutus 	ioat_state_t *state;
327*6707Sbrutus 	int instance;
328*6707Sbrutus 	dev_t dev;
329*6707Sbrutus 	int e;
330*6707Sbrutus 
331*6707Sbrutus 
332*6707Sbrutus 	dev = (dev_t)arg;
333*6707Sbrutus 	instance = getminor(dev);
334*6707Sbrutus 
335*6707Sbrutus 	switch (cmd) {
336*6707Sbrutus 	case DDI_INFO_DEVT2DEVINFO:
337*6707Sbrutus 		state = ddi_get_soft_state(ioat_statep, instance);
338*6707Sbrutus 		if (state == NULL) {
339*6707Sbrutus 			return (DDI_FAILURE);
340*6707Sbrutus 		}
341*6707Sbrutus 		*result = (void *)state->is_dip;
342*6707Sbrutus 		e = DDI_SUCCESS;
343*6707Sbrutus 		break;
344*6707Sbrutus 
345*6707Sbrutus 	case DDI_INFO_DEVT2INSTANCE:
346*6707Sbrutus 		*result = (void *)(uintptr_t)instance;
347*6707Sbrutus 		e = DDI_SUCCESS;
348*6707Sbrutus 		break;
349*6707Sbrutus 
350*6707Sbrutus 	default:
351*6707Sbrutus 		e = DDI_FAILURE;
352*6707Sbrutus 		break;
353*6707Sbrutus 	}
354*6707Sbrutus 
355*6707Sbrutus 	return (e);
356*6707Sbrutus }
357*6707Sbrutus 
358*6707Sbrutus 
359*6707Sbrutus /*
360*6707Sbrutus  * ioat_open()
361*6707Sbrutus  */
362*6707Sbrutus /*ARGSUSED*/
363*6707Sbrutus static int
364*6707Sbrutus ioat_open(dev_t *devp, int flag, int otyp, cred_t *cred)
365*6707Sbrutus {
366*6707Sbrutus 	ioat_state_t *state;
367*6707Sbrutus 	int instance;
368*6707Sbrutus 
369*6707Sbrutus 	instance = getminor(*devp);
370*6707Sbrutus 	state = ddi_get_soft_state(ioat_statep, instance);
371*6707Sbrutus 	if (state == NULL) {
372*6707Sbrutus 		return (ENXIO);
373*6707Sbrutus 	}
374*6707Sbrutus 
375*6707Sbrutus 	return (0);
376*6707Sbrutus }
377*6707Sbrutus 
378*6707Sbrutus 
379*6707Sbrutus /*
380*6707Sbrutus  * ioat_close()
381*6707Sbrutus  */
382*6707Sbrutus /*ARGSUSED*/
383*6707Sbrutus static int
384*6707Sbrutus ioat_close(dev_t devp, int flag, int otyp, cred_t *cred)
385*6707Sbrutus {
386*6707Sbrutus 	return (0);
387*6707Sbrutus }
388*6707Sbrutus 
389*6707Sbrutus 
390*6707Sbrutus /*
391*6707Sbrutus  * ioat_chip_init()
392*6707Sbrutus  */
393*6707Sbrutus static int
394*6707Sbrutus ioat_chip_init(ioat_state_t *state)
395*6707Sbrutus {
396*6707Sbrutus 	ddi_device_acc_attr_t attr;
397*6707Sbrutus 	int e;
398*6707Sbrutus 
399*6707Sbrutus 
400*6707Sbrutus 	attr.devacc_attr_version = DDI_DEVICE_ATTR_V0;
401*6707Sbrutus 	attr.devacc_attr_endian_flags = DDI_NEVERSWAP_ACC;
402*6707Sbrutus 	attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC;
403*6707Sbrutus 
404*6707Sbrutus 	e =  ddi_regs_map_setup(state->is_dip, 1, (caddr_t *)&state->is_genregs,
405*6707Sbrutus 	    0, 0, &attr, &state->is_reg_handle);
406*6707Sbrutus 	if (e != DDI_SUCCESS) {
407*6707Sbrutus 		goto chipinitfail_regsmap;
408*6707Sbrutus 	}
409*6707Sbrutus 
410*6707Sbrutus 	/* save away ioat chip info */
411*6707Sbrutus 	state->is_num_channels = (uint_t)ddi_get8(state->is_reg_handle,
412*6707Sbrutus 	    &state->is_genregs[IOAT_CHANCNT]);
413*6707Sbrutus 	state->is_maxxfer = (uint_t)ddi_get8(state->is_reg_handle,
414*6707Sbrutus 	    &state->is_genregs[IOAT_XFERCAP]);
415*6707Sbrutus 	state->is_chanoff = (uintptr_t)ddi_get16(state->is_reg_handle,
416*6707Sbrutus 	    (uint16_t *)&state->is_genregs[IOAT_PERPORT_OFF]);
417*6707Sbrutus 	state->is_cbver = (uint_t)ddi_get8(state->is_reg_handle,
418*6707Sbrutus 	    &state->is_genregs[IOAT_CBVER]);
419*6707Sbrutus 	state->is_intrdelay = (uint_t)ddi_get16(state->is_reg_handle,
420*6707Sbrutus 	    (uint16_t *)&state->is_genregs[IOAT_INTRDELAY]);
421*6707Sbrutus 	state->is_status = (uint_t)ddi_get16(state->is_reg_handle,
422*6707Sbrutus 	    (uint16_t *)&state->is_genregs[IOAT_CSSTATUS]);
423*6707Sbrutus 	state->is_capabilities = (uint_t)ddi_get32(state->is_reg_handle,
424*6707Sbrutus 	    (uint32_t *)&state->is_genregs[IOAT_DMACAPABILITY]);
425*6707Sbrutus 
426*6707Sbrutus 	if (state->is_cbver & 0x10) {
427*6707Sbrutus 		state->is_ver = IOAT_CBv1;
428*6707Sbrutus 	} else if (state->is_cbver & 0x20) {
429*6707Sbrutus 		state->is_ver = IOAT_CBv2;
430*6707Sbrutus 	} else {
431*6707Sbrutus 		goto chipinitfail_version;
432*6707Sbrutus 	}
433*6707Sbrutus 
434*6707Sbrutus 	return (DDI_SUCCESS);
435*6707Sbrutus 
436*6707Sbrutus chipinitfail_version:
437*6707Sbrutus 	ddi_regs_map_free(&state->is_reg_handle);
438*6707Sbrutus chipinitfail_regsmap:
439*6707Sbrutus 	return (DDI_FAILURE);
440*6707Sbrutus }
441*6707Sbrutus 
442*6707Sbrutus 
443*6707Sbrutus /*
444*6707Sbrutus  * ioat_chip_fini()
445*6707Sbrutus  */
446*6707Sbrutus static void
447*6707Sbrutus ioat_chip_fini(ioat_state_t *state)
448*6707Sbrutus {
449*6707Sbrutus 	ddi_regs_map_free(&state->is_reg_handle);
450*6707Sbrutus }
451*6707Sbrutus 
452*6707Sbrutus 
453*6707Sbrutus /*
454*6707Sbrutus  * ioat_drv_init()
455*6707Sbrutus  */
456*6707Sbrutus static int
457*6707Sbrutus ioat_drv_init(ioat_state_t *state)
458*6707Sbrutus {
459*6707Sbrutus 	ddi_acc_handle_t handle;
460*6707Sbrutus 	int e;
461*6707Sbrutus 
462*6707Sbrutus 
463*6707Sbrutus 	mutex_init(&state->is_mutex, NULL, MUTEX_DRIVER, NULL);
464*6707Sbrutus 
465*6707Sbrutus 	state->is_deviceinfo.di_dip = state->is_dip;
466*6707Sbrutus 	state->is_deviceinfo.di_num_dma = state->is_num_channels;
467*6707Sbrutus 	state->is_deviceinfo.di_maxxfer = state->is_maxxfer;
468*6707Sbrutus 	state->is_deviceinfo.di_capabilities = state->is_capabilities;
469*6707Sbrutus 	state->is_deviceinfo.di_cb = &ioat_cb;
470*6707Sbrutus 
471*6707Sbrutus 	e = pci_config_setup(state->is_dip, &handle);
472*6707Sbrutus 	if (e != DDI_SUCCESS) {
473*6707Sbrutus 		goto drvinitfail_config_setup;
474*6707Sbrutus 	}
475*6707Sbrutus 
476*6707Sbrutus 	/* read in Vendor ID */
477*6707Sbrutus 	state->is_deviceinfo.di_id = (uint64_t)pci_config_get16(handle, 0);
478*6707Sbrutus 	state->is_deviceinfo.di_id = state->is_deviceinfo.di_id << 16;
479*6707Sbrutus 
480*6707Sbrutus 	/* read in Device ID */
481*6707Sbrutus 	state->is_deviceinfo.di_id |= (uint64_t)pci_config_get16(handle, 2);
482*6707Sbrutus 	state->is_deviceinfo.di_id = state->is_deviceinfo.di_id << 32;
483*6707Sbrutus 
484*6707Sbrutus 	/* Add in chipset version */
485*6707Sbrutus 	state->is_deviceinfo.di_id |= (uint64_t)state->is_cbver;
486*6707Sbrutus 	pci_config_teardown(&handle);
487*6707Sbrutus 
488*6707Sbrutus 	e = ddi_intr_hilevel(state->is_dip, 0);
489*6707Sbrutus 	if (e != 0) {
490*6707Sbrutus 		cmn_err(CE_WARN, "hilevel interrupt not supported\n");
491*6707Sbrutus 		goto drvinitfail_hilevel;
492*6707Sbrutus 	}
493*6707Sbrutus 
494*6707Sbrutus 	/* we don't support MSIs for v2 yet */
495*6707Sbrutus 	e = ddi_add_intr(state->is_dip, 0, NULL, NULL, ioat_isr,
496*6707Sbrutus 	    (caddr_t)state);
497*6707Sbrutus 	if (e != DDI_SUCCESS) {
498*6707Sbrutus 		goto drvinitfail_add_intr;
499*6707Sbrutus 	}
500*6707Sbrutus 
501*6707Sbrutus 	e = ddi_get_iblock_cookie(state->is_dip, 0, &state->is_iblock_cookie);
502*6707Sbrutus 	if (e != DDI_SUCCESS) {
503*6707Sbrutus 		goto drvinitfail_iblock_cookie;
504*6707Sbrutus 	}
505*6707Sbrutus 
506*6707Sbrutus 	e = ioat_channel_init(state);
507*6707Sbrutus 	if (e != DDI_SUCCESS) {
508*6707Sbrutus 		goto drvinitfail_channel_init;
509*6707Sbrutus 	}
510*6707Sbrutus 
511*6707Sbrutus 	return (DDI_SUCCESS);
512*6707Sbrutus 
513*6707Sbrutus drvinitfail_channel_init:
514*6707Sbrutus drvinitfail_iblock_cookie:
515*6707Sbrutus 	ddi_remove_intr(state->is_dip, 0, state->is_iblock_cookie);
516*6707Sbrutus drvinitfail_add_intr:
517*6707Sbrutus drvinitfail_hilevel:
518*6707Sbrutus drvinitfail_config_setup:
519*6707Sbrutus 	mutex_destroy(&state->is_mutex);
520*6707Sbrutus 
521*6707Sbrutus 	return (DDI_FAILURE);
522*6707Sbrutus }
523*6707Sbrutus 
524*6707Sbrutus 
525*6707Sbrutus /*
526*6707Sbrutus  * ioat_drv_fini()
527*6707Sbrutus  */
528*6707Sbrutus static void
529*6707Sbrutus ioat_drv_fini(ioat_state_t *state)
530*6707Sbrutus {
531*6707Sbrutus 	ioat_channel_fini(state);
532*6707Sbrutus 	ddi_remove_intr(state->is_dip, 0, state->is_iblock_cookie);
533*6707Sbrutus 	mutex_destroy(&state->is_mutex);
534*6707Sbrutus }
535*6707Sbrutus 
536*6707Sbrutus 
537*6707Sbrutus /*
538*6707Sbrutus  * ioat_unregister_complete()
539*6707Sbrutus  */
540*6707Sbrutus void
541*6707Sbrutus ioat_unregister_complete(void *device_private, int status)
542*6707Sbrutus {
543*6707Sbrutus 	ioat_state_t *state;
544*6707Sbrutus 
545*6707Sbrutus 
546*6707Sbrutus 	state = device_private;
547*6707Sbrutus 
548*6707Sbrutus 	if (status != DCOPY_SUCCESS) {
549*6707Sbrutus 		cmn_err(CE_WARN, "asynchronous detach aborted\n");
550*6707Sbrutus 		return;
551*6707Sbrutus 	}
552*6707Sbrutus 
553*6707Sbrutus 	cmn_err(CE_CONT, "detach completing\n");
554*6707Sbrutus 	ioat_detach_finish(state);
555*6707Sbrutus }
556*6707Sbrutus 
557*6707Sbrutus 
558*6707Sbrutus /*
559*6707Sbrutus  * ioat_detach_finish()
560*6707Sbrutus  */
561*6707Sbrutus void
562*6707Sbrutus ioat_detach_finish(ioat_state_t *state)
563*6707Sbrutus {
564*6707Sbrutus 	ioat_intr_disable(state);
565*6707Sbrutus 	ddi_remove_minor_node(state->is_dip, NULL);
566*6707Sbrutus 	ioat_drv_fini(state);
567*6707Sbrutus 	ioat_chip_fini(state);
568*6707Sbrutus 	(void) ddi_soft_state_free(ioat_statep, state->is_instance);
569*6707Sbrutus }
570*6707Sbrutus 
571*6707Sbrutus 
572*6707Sbrutus /*
573*6707Sbrutus  * ioat_intr_enable()
574*6707Sbrutus  */
575*6707Sbrutus static void
576*6707Sbrutus ioat_intr_enable(ioat_state_t *state)
577*6707Sbrutus {
578*6707Sbrutus 	uint32_t intr_status;
579*6707Sbrutus 
580*6707Sbrutus 
581*6707Sbrutus 	/* Clear any pending interrupts */
582*6707Sbrutus 	intr_status = ddi_get32(state->is_reg_handle,
583*6707Sbrutus 	    (uint32_t *)&state->is_genregs[IOAT_ATTNSTATUS]);
584*6707Sbrutus 	if (intr_status != 0) {
585*6707Sbrutus 		ddi_put32(state->is_reg_handle,
586*6707Sbrutus 		    (uint32_t *)&state->is_genregs[IOAT_ATTNSTATUS],
587*6707Sbrutus 		    intr_status);
588*6707Sbrutus 	}
589*6707Sbrutus 
590*6707Sbrutus 	/* Enable interrupts on the device */
591*6707Sbrutus 	ddi_put8(state->is_reg_handle, &state->is_genregs[IOAT_INTRCTL],
592*6707Sbrutus 	    IOAT_INTRCTL_MASTER_EN);
593*6707Sbrutus }
594*6707Sbrutus 
595*6707Sbrutus 
596*6707Sbrutus /*
597*6707Sbrutus  * ioat_intr_disable()
598*6707Sbrutus  */
599*6707Sbrutus static void
600*6707Sbrutus ioat_intr_disable(ioat_state_t *state)
601*6707Sbrutus {
602*6707Sbrutus 	/*
603*6707Sbrutus 	 * disable interrupts on the device. A read of the interrupt control
604*6707Sbrutus 	 * register clears the enable bit.
605*6707Sbrutus 	 */
606*6707Sbrutus 	(void) ddi_get8(state->is_reg_handle,
607*6707Sbrutus 	    &state->is_genregs[IOAT_INTRCTL]);
608*6707Sbrutus }
609*6707Sbrutus 
610*6707Sbrutus 
611*6707Sbrutus /*
612*6707Sbrutus  * ioat_isr()
613*6707Sbrutus  */
614*6707Sbrutus static uint_t
615*6707Sbrutus ioat_isr(caddr_t parm)
616*6707Sbrutus {
617*6707Sbrutus 	uint32_t intr_status;
618*6707Sbrutus 	ioat_state_t *state;
619*6707Sbrutus 	uint8_t intrctrl;
620*6707Sbrutus 	uint32_t chan;
621*6707Sbrutus 	uint_t r;
622*6707Sbrutus 	int i;
623*6707Sbrutus 
624*6707Sbrutus 	state = (ioat_state_t *)parm;
625*6707Sbrutus 
626*6707Sbrutus 	intrctrl = ddi_get8(state->is_reg_handle,
627*6707Sbrutus 	    &state->is_genregs[IOAT_INTRCTL]);
628*6707Sbrutus 	/* master interrupt enable should always be set */
629*6707Sbrutus 	ASSERT(intrctrl & IOAT_INTRCTL_MASTER_EN);
630*6707Sbrutus 
631*6707Sbrutus 	/* If the interrupt status bit isn't set, it's not ours */
632*6707Sbrutus 	if (!(intrctrl & IOAT_INTRCTL_INTR_STAT)) {
633*6707Sbrutus 		/* re-set master interrupt enable (since it clears on read) */
634*6707Sbrutus 		ddi_put8(state->is_reg_handle,
635*6707Sbrutus 		    &state->is_genregs[IOAT_INTRCTL], intrctrl);
636*6707Sbrutus 		return (DDI_INTR_UNCLAIMED);
637*6707Sbrutus 	}
638*6707Sbrutus 
639*6707Sbrutus 	/* see which channels generated the interrupt */
640*6707Sbrutus 	intr_status = ddi_get32(state->is_reg_handle,
641*6707Sbrutus 	    (uint32_t *)&state->is_genregs[IOAT_ATTNSTATUS]);
642*6707Sbrutus 
643*6707Sbrutus 	/* call the intr handler for the channels */
644*6707Sbrutus 	r = DDI_INTR_UNCLAIMED;
645*6707Sbrutus 	chan = 1;
646*6707Sbrutus 	for (i = 0; i < state->is_num_channels; i++) {
647*6707Sbrutus 		if (intr_status & chan) {
648*6707Sbrutus 			ioat_channel_intr(&state->is_channel[i]);
649*6707Sbrutus 			r = DDI_INTR_CLAIMED;
650*6707Sbrutus 		}
651*6707Sbrutus 		chan = chan << 1;
652*6707Sbrutus 	}
653*6707Sbrutus 
654*6707Sbrutus 	/*
655*6707Sbrutus 	 * if interrupt status bit was set, there should have been an
656*6707Sbrutus 	 * attention status bit set too.
657*6707Sbrutus 	 */
658*6707Sbrutus 	ASSERT(r == DDI_INTR_CLAIMED);
659*6707Sbrutus 
660*6707Sbrutus 	/* re-set master interrupt enable (since it clears on read) */
661*6707Sbrutus 	ddi_put8(state->is_reg_handle, &state->is_genregs[IOAT_INTRCTL],
662*6707Sbrutus 	    intrctrl);
663*6707Sbrutus 
664*6707Sbrutus 	return (r);
665*6707Sbrutus }
666