xref: /onnv-gate/usr/src/uts/i86pc/io/ioat/ioat.c (revision 7656:2621e50fdf4a)
16707Sbrutus /*
26707Sbrutus  * CDDL HEADER START
36707Sbrutus  *
46707Sbrutus  * The contents of this file are subject to the terms of the
56707Sbrutus  * Common Development and Distribution License (the "License").
66707Sbrutus  * You may not use this file except in compliance with the License.
76707Sbrutus  *
86707Sbrutus  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
96707Sbrutus  * or http://www.opensolaris.org/os/licensing.
106707Sbrutus  * See the License for the specific language governing permissions
116707Sbrutus  * and limitations under the License.
126707Sbrutus  *
136707Sbrutus  * When distributing Covered Code, include this CDDL HEADER in each
146707Sbrutus  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
156707Sbrutus  * If applicable, add the following below this CDDL HEADER, with the
166707Sbrutus  * fields enclosed by brackets "[]" replaced with your own identifying
176707Sbrutus  * information: Portions Copyright [yyyy] [name of copyright owner]
186707Sbrutus  *
196707Sbrutus  * CDDL HEADER END
206707Sbrutus  */
216707Sbrutus 
226707Sbrutus /*
236707Sbrutus  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
246707Sbrutus  * Use is subject to license terms.
256707Sbrutus  */
266707Sbrutus 
276707Sbrutus #include <sys/errno.h>
286707Sbrutus #include <sys/types.h>
296707Sbrutus #include <sys/conf.h>
306707Sbrutus #include <sys/kmem.h>
316707Sbrutus #include <sys/ddi.h>
326707Sbrutus #include <sys/stat.h>
336707Sbrutus #include <sys/sunddi.h>
346707Sbrutus #include <sys/file.h>
356707Sbrutus #include <sys/open.h>
366707Sbrutus #include <sys/modctl.h>
376707Sbrutus #include <sys/ddi_impldefs.h>
386707Sbrutus #include <sys/sysmacros.h>
396707Sbrutus 
406707Sbrutus #include <sys/ioat.h>
416707Sbrutus 
426707Sbrutus static int ioat_open(dev_t *devp, int flag, int otyp, cred_t *cred);
436707Sbrutus static int ioat_close(dev_t devp, int flag, int otyp, cred_t *cred);
446707Sbrutus static int ioat_attach(dev_info_t *devi, ddi_attach_cmd_t cmd);
456707Sbrutus static int ioat_detach(dev_info_t *devi, ddi_detach_cmd_t cmd);
466707Sbrutus static int ioat_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg,
476707Sbrutus     void **result);
48*7656SSherry.Moore@Sun.COM static int ioat_quiesce(dev_info_t *dip);
496707Sbrutus 
506707Sbrutus static 	struct cb_ops ioat_cb_ops = {
516707Sbrutus 	ioat_open,		/* cb_open */
526707Sbrutus 	ioat_close,		/* cb_close */
536707Sbrutus 	nodev,			/* cb_strategy */
546707Sbrutus 	nodev,			/* cb_print */
556707Sbrutus 	nodev,			/* cb_dump */
566707Sbrutus 	nodev,			/* cb_read */
576707Sbrutus 	nodev,			/* cb_write */
586707Sbrutus 	ioat_ioctl,		/* cb_ioctl */
596707Sbrutus 	nodev,			/* cb_devmap */
606707Sbrutus 	nodev,			/* cb_mmap */
616707Sbrutus 	nodev,			/* cb_segmap */
626707Sbrutus 	nochpoll,		/* cb_chpoll */
636707Sbrutus 	ddi_prop_op,		/* cb_prop_op */
646707Sbrutus 	NULL,			/* cb_stream */
656707Sbrutus 	D_NEW | D_MP | D_64BIT | D_DEVMAP,	/* cb_flag */
666707Sbrutus 	CB_REV
676707Sbrutus };
686707Sbrutus 
696707Sbrutus static struct dev_ops ioat_dev_ops = {
706707Sbrutus 	DEVO_REV,		/* devo_rev */
716707Sbrutus 	0,			/* devo_refcnt */
726707Sbrutus 	ioat_getinfo,		/* devo_getinfo */
736707Sbrutus 	nulldev,		/* devo_identify */
746707Sbrutus 	nulldev,		/* devo_probe */
756707Sbrutus 	ioat_attach,		/* devo_attach */
766707Sbrutus 	ioat_detach,		/* devo_detach */
776707Sbrutus 	nodev,			/* devo_reset */
786707Sbrutus 	&ioat_cb_ops,		/* devo_cb_ops */
796707Sbrutus 	NULL,			/* devo_bus_ops */
80*7656SSherry.Moore@Sun.COM 	NULL,			/* devo_power */
81*7656SSherry.Moore@Sun.COM 	ioat_quiesce,		/* devo_quiesce */
826707Sbrutus };
836707Sbrutus 
846707Sbrutus static struct modldrv ioat_modldrv = {
856707Sbrutus 	&mod_driverops,		/* Type of module.  This one is a driver */
867542SRichard.Bean@Sun.COM 	"ioat driver",		/* Name of the module. */
876707Sbrutus 	&ioat_dev_ops,		/* driver ops */
886707Sbrutus };
896707Sbrutus 
906707Sbrutus static struct modlinkage ioat_modlinkage = {
916707Sbrutus 	MODREV_1,
926707Sbrutus 	(void *) &ioat_modldrv,
936707Sbrutus 	NULL
946707Sbrutus };
956707Sbrutus 
966707Sbrutus 
976707Sbrutus void *ioat_statep;
986707Sbrutus 
996707Sbrutus static int ioat_chip_init(ioat_state_t *state);
1006707Sbrutus static void ioat_chip_fini(ioat_state_t *state);
1016707Sbrutus static int ioat_drv_init(ioat_state_t *state);
1026707Sbrutus static void ioat_drv_fini(ioat_state_t *state);
1036707Sbrutus static uint_t ioat_isr(caddr_t parm);
1046707Sbrutus static void ioat_intr_enable(ioat_state_t *state);
1056707Sbrutus static void ioat_intr_disable(ioat_state_t *state);
1066707Sbrutus void ioat_detach_finish(ioat_state_t *state);
1076707Sbrutus 
1086707Sbrutus 
1096707Sbrutus ddi_device_acc_attr_t ioat_acc_attr = {
1106707Sbrutus 	DDI_DEVICE_ATTR_V0,		/* devacc_attr_version */
1116707Sbrutus 	DDI_NEVERSWAP_ACC,		/* devacc_attr_endian_flags */
1126707Sbrutus 	DDI_STORECACHING_OK_ACC,	/* devacc_attr_dataorder */
1136707Sbrutus 	DDI_DEFAULT_ACC			/* devacc_attr_access */
1146707Sbrutus };
1156707Sbrutus 
1166707Sbrutus /* dcopy callback interface */
1176707Sbrutus dcopy_device_cb_t ioat_cb = {
1186707Sbrutus 	DCOPY_DEVICECB_V0,
1196707Sbrutus 	0,		/* reserved */
1206707Sbrutus 	ioat_channel_alloc,
1216707Sbrutus 	ioat_channel_free,
1226707Sbrutus 	ioat_cmd_alloc,
1236707Sbrutus 	ioat_cmd_free,
1246707Sbrutus 	ioat_cmd_post,
1256707Sbrutus 	ioat_cmd_poll,
1266707Sbrutus 	ioat_unregister_complete
1276707Sbrutus };
1286707Sbrutus 
1296707Sbrutus /*
1306707Sbrutus  * _init()
1316707Sbrutus  */
1326707Sbrutus int
_init(void)1336707Sbrutus _init(void)
1346707Sbrutus {
1356707Sbrutus 	int e;
1366707Sbrutus 
1376707Sbrutus 	e = ddi_soft_state_init(&ioat_statep, sizeof (ioat_state_t), 1);
1386707Sbrutus 	if (e != 0) {
1396707Sbrutus 		return (e);
1406707Sbrutus 	}
1416707Sbrutus 
1426707Sbrutus 	e = mod_install(&ioat_modlinkage);
1436707Sbrutus 	if (e != 0) {
1446707Sbrutus 		ddi_soft_state_fini(&ioat_statep);
1456707Sbrutus 		return (e);
1466707Sbrutus 	}
1476707Sbrutus 
1486707Sbrutus 	return (0);
1496707Sbrutus }
1506707Sbrutus 
1516707Sbrutus /*
1526707Sbrutus  * _info()
1536707Sbrutus  */
1546707Sbrutus int
_info(struct modinfo * modinfop)1556707Sbrutus _info(struct modinfo *modinfop)
1566707Sbrutus {
1576707Sbrutus 	return (mod_info(&ioat_modlinkage, modinfop));
1586707Sbrutus }
1596707Sbrutus 
1606707Sbrutus /*
1616707Sbrutus  * _fini()
1626707Sbrutus  */
1636707Sbrutus int
_fini(void)1646707Sbrutus _fini(void)
1656707Sbrutus {
1666707Sbrutus 	int e;
1676707Sbrutus 
1686707Sbrutus 	e = mod_remove(&ioat_modlinkage);
1696707Sbrutus 	if (e != 0) {
1706707Sbrutus 		return (e);
1716707Sbrutus 	}
1726707Sbrutus 
1736707Sbrutus 	ddi_soft_state_fini(&ioat_statep);
1746707Sbrutus 
1756707Sbrutus 	return (0);
1766707Sbrutus }
1776707Sbrutus 
1786707Sbrutus /*
1796707Sbrutus  * ioat_attach()
1806707Sbrutus  */
1816707Sbrutus static int
ioat_attach(dev_info_t * dip,ddi_attach_cmd_t cmd)1826707Sbrutus ioat_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
1836707Sbrutus {
1846707Sbrutus 	ioat_state_t *state;
1856707Sbrutus 	int instance;
1866707Sbrutus 	int e;
1876707Sbrutus 
1886707Sbrutus 
1896707Sbrutus 	switch (cmd) {
1906707Sbrutus 	case DDI_ATTACH:
1916707Sbrutus 		break;
1926707Sbrutus 
1936707Sbrutus 	case DDI_RESUME:
1946707Sbrutus 		instance = ddi_get_instance(dip);
1956707Sbrutus 		state = ddi_get_soft_state(ioat_statep, instance);
1966707Sbrutus 		if (state == NULL) {
1976707Sbrutus 			return (DDI_FAILURE);
1986707Sbrutus 		}
1996707Sbrutus 		e = ioat_channel_resume(state);
2006707Sbrutus 		if (e != DDI_SUCCESS) {
2016707Sbrutus 			return (DDI_FAILURE);
2026707Sbrutus 		}
2036707Sbrutus 		ioat_intr_enable(state);
2046707Sbrutus 		return (DDI_SUCCESS);
2056707Sbrutus 
2066707Sbrutus 	default:
2076707Sbrutus 		return (DDI_FAILURE);
2086707Sbrutus 	}
2096707Sbrutus 
2106707Sbrutus 	instance = ddi_get_instance(dip);
2116707Sbrutus 	e = ddi_soft_state_zalloc(ioat_statep, instance);
2126707Sbrutus 	if (e != DDI_SUCCESS) {
2136707Sbrutus 		return (DDI_FAILURE);
2146707Sbrutus 	}
2156707Sbrutus 	state = ddi_get_soft_state(ioat_statep, instance);
2166707Sbrutus 	if (state == NULL) {
2176707Sbrutus 		goto attachfail_get_soft_state;
2186707Sbrutus 	}
2196707Sbrutus 
2206707Sbrutus 	state->is_dip = dip;
2216707Sbrutus 	state->is_instance = instance;
2226707Sbrutus 
2236707Sbrutus 	/* setup the registers, save away some device info */
2246707Sbrutus 	e = ioat_chip_init(state);
2256707Sbrutus 	if (e != DDI_SUCCESS) {
2266707Sbrutus 		goto attachfail_chip_init;
2276707Sbrutus 	}
2286707Sbrutus 
2296707Sbrutus 	/* initialize driver state, must be after chip init */
2306707Sbrutus 	e = ioat_drv_init(state);
2316707Sbrutus 	if (e != DDI_SUCCESS) {
2326707Sbrutus 		goto attachfail_drv_init;
2336707Sbrutus 	}
2346707Sbrutus 
2356707Sbrutus 	/* create the minor node (for the ioctl) */
2366707Sbrutus 	e = ddi_create_minor_node(dip, "ioat", S_IFCHR, instance, DDI_PSEUDO,
2376707Sbrutus 	    0);
2386707Sbrutus 	if (e != DDI_SUCCESS) {
2396707Sbrutus 		goto attachfail_minor_node;
2406707Sbrutus 	}
2416707Sbrutus 
2426707Sbrutus 	/* Enable device interrupts */
2436707Sbrutus 	ioat_intr_enable(state);
2446707Sbrutus 
2456707Sbrutus 	/* Report that driver was loaded */
2466707Sbrutus 	ddi_report_dev(dip);
2476707Sbrutus 
2486707Sbrutus 	/* register with dcopy */
2496707Sbrutus 	e = dcopy_device_register(state, &state->is_deviceinfo,
2506707Sbrutus 	    &state->is_device_handle);
2516707Sbrutus 	if (e != DCOPY_SUCCESS) {
2526707Sbrutus 		goto attachfail_register;
2536707Sbrutus 	}
2546707Sbrutus 
2556707Sbrutus 	return (DDI_SUCCESS);
2566707Sbrutus 
2576707Sbrutus attachfail_register:
2586707Sbrutus 	ioat_intr_disable(state);
2596707Sbrutus 	ddi_remove_minor_node(dip, NULL);
2606707Sbrutus attachfail_minor_node:
2616707Sbrutus 	ioat_drv_fini(state);
2626707Sbrutus attachfail_drv_init:
2636707Sbrutus 	ioat_chip_fini(state);
2646707Sbrutus attachfail_chip_init:
2656707Sbrutus attachfail_get_soft_state:
2666707Sbrutus 	(void) ddi_soft_state_free(ioat_statep, instance);
2676707Sbrutus 
2686707Sbrutus 	return (DDI_FAILURE);
2696707Sbrutus }
2706707Sbrutus 
2716707Sbrutus /*
2726707Sbrutus  * ioat_detach()
2736707Sbrutus  */
2746707Sbrutus static int
ioat_detach(dev_info_t * dip,ddi_detach_cmd_t cmd)2756707Sbrutus ioat_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
2766707Sbrutus {
2776707Sbrutus 	ioat_state_t *state;
2786707Sbrutus 	int instance;
2796707Sbrutus 	int e;
2806707Sbrutus 
2816707Sbrutus 
2826707Sbrutus 	instance = ddi_get_instance(dip);
2836707Sbrutus 	state = ddi_get_soft_state(ioat_statep, instance);
2846707Sbrutus 	if (state == NULL) {
2856707Sbrutus 		return (DDI_FAILURE);
2866707Sbrutus 	}
2876707Sbrutus 
2886707Sbrutus 	switch (cmd) {
2896707Sbrutus 	case DDI_DETACH:
2906707Sbrutus 		break;
2916707Sbrutus 
2926707Sbrutus 	case DDI_SUSPEND:
2936707Sbrutus 		ioat_channel_suspend(state);
2946707Sbrutus 		return (DDI_SUCCESS);
2956707Sbrutus 
2966707Sbrutus 	default:
2976707Sbrutus 		return (DDI_FAILURE);
2986707Sbrutus 	}
2996707Sbrutus 
3006707Sbrutus 	/*
3016707Sbrutus 	 * try to unregister from dcopy.  Since this driver doesn't follow the
3026707Sbrutus 	 * traditional parent/child model, we may still be in use so we can't
3036707Sbrutus 	 * detach yet.
3046707Sbrutus 	 */
3056707Sbrutus 	e = dcopy_device_unregister(&state->is_device_handle);
3066707Sbrutus 	if (e != DCOPY_SUCCESS) {
3076707Sbrutus 		if (e == DCOPY_PENDING) {
3086707Sbrutus 			cmn_err(CE_NOTE, "device busy, performing asynchronous"
3096707Sbrutus 			    " detach\n");
3106707Sbrutus 		}
3116707Sbrutus 		return (DDI_FAILURE);
3126707Sbrutus 	}
3136707Sbrutus 
3146707Sbrutus 	ioat_detach_finish(state);
3156707Sbrutus 
3166707Sbrutus 	return (DDI_SUCCESS);
3176707Sbrutus }
3186707Sbrutus 
3196707Sbrutus /*
3206707Sbrutus  * ioat_getinfo()
3216707Sbrutus  */
3226707Sbrutus /*ARGSUSED*/
3236707Sbrutus static int
ioat_getinfo(dev_info_t * dip,ddi_info_cmd_t cmd,void * arg,void ** result)3246707Sbrutus ioat_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **result)
3256707Sbrutus {
3266707Sbrutus 	ioat_state_t *state;
3276707Sbrutus 	int instance;
3286707Sbrutus 	dev_t dev;
3296707Sbrutus 	int e;
3306707Sbrutus 
3316707Sbrutus 
3326707Sbrutus 	dev = (dev_t)arg;
3336707Sbrutus 	instance = getminor(dev);
3346707Sbrutus 
3356707Sbrutus 	switch (cmd) {
3366707Sbrutus 	case DDI_INFO_DEVT2DEVINFO:
3376707Sbrutus 		state = ddi_get_soft_state(ioat_statep, instance);
3386707Sbrutus 		if (state == NULL) {
3396707Sbrutus 			return (DDI_FAILURE);
3406707Sbrutus 		}
3416707Sbrutus 		*result = (void *)state->is_dip;
3426707Sbrutus 		e = DDI_SUCCESS;
3436707Sbrutus 		break;
3446707Sbrutus 
3456707Sbrutus 	case DDI_INFO_DEVT2INSTANCE:
3466707Sbrutus 		*result = (void *)(uintptr_t)instance;
3476707Sbrutus 		e = DDI_SUCCESS;
3486707Sbrutus 		break;
3496707Sbrutus 
3506707Sbrutus 	default:
3516707Sbrutus 		e = DDI_FAILURE;
3526707Sbrutus 		break;
3536707Sbrutus 	}
3546707Sbrutus 
3556707Sbrutus 	return (e);
3566707Sbrutus }
3576707Sbrutus 
3586707Sbrutus 
3596707Sbrutus /*
3606707Sbrutus  * ioat_open()
3616707Sbrutus  */
3626707Sbrutus /*ARGSUSED*/
3636707Sbrutus static int
ioat_open(dev_t * devp,int flag,int otyp,cred_t * cred)3646707Sbrutus ioat_open(dev_t *devp, int flag, int otyp, cred_t *cred)
3656707Sbrutus {
3666707Sbrutus 	ioat_state_t *state;
3676707Sbrutus 	int instance;
3686707Sbrutus 
3696707Sbrutus 	instance = getminor(*devp);
3706707Sbrutus 	state = ddi_get_soft_state(ioat_statep, instance);
3716707Sbrutus 	if (state == NULL) {
3726707Sbrutus 		return (ENXIO);
3736707Sbrutus 	}
3746707Sbrutus 
3756707Sbrutus 	return (0);
3766707Sbrutus }
3776707Sbrutus 
3786707Sbrutus 
3796707Sbrutus /*
3806707Sbrutus  * ioat_close()
3816707Sbrutus  */
3826707Sbrutus /*ARGSUSED*/
3836707Sbrutus static int
ioat_close(dev_t devp,int flag,int otyp,cred_t * cred)3846707Sbrutus ioat_close(dev_t devp, int flag, int otyp, cred_t *cred)
3856707Sbrutus {
3866707Sbrutus 	return (0);
3876707Sbrutus }
3886707Sbrutus 
3896707Sbrutus 
3906707Sbrutus /*
3916707Sbrutus  * ioat_chip_init()
3926707Sbrutus  */
3936707Sbrutus static int
ioat_chip_init(ioat_state_t * state)3946707Sbrutus ioat_chip_init(ioat_state_t *state)
3956707Sbrutus {
3966707Sbrutus 	ddi_device_acc_attr_t attr;
3976707Sbrutus 	int e;
3986707Sbrutus 
3996707Sbrutus 
4006707Sbrutus 	attr.devacc_attr_version = DDI_DEVICE_ATTR_V0;
4016707Sbrutus 	attr.devacc_attr_endian_flags = DDI_NEVERSWAP_ACC;
4026707Sbrutus 	attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC;
4036707Sbrutus 
4046707Sbrutus 	e =  ddi_regs_map_setup(state->is_dip, 1, (caddr_t *)&state->is_genregs,
4056707Sbrutus 	    0, 0, &attr, &state->is_reg_handle);
4066707Sbrutus 	if (e != DDI_SUCCESS) {
4076707Sbrutus 		goto chipinitfail_regsmap;
4086707Sbrutus 	}
4096707Sbrutus 
4106707Sbrutus 	/* save away ioat chip info */
4116707Sbrutus 	state->is_num_channels = (uint_t)ddi_get8(state->is_reg_handle,
4126707Sbrutus 	    &state->is_genregs[IOAT_CHANCNT]);
4137075Smrj 
4147075Smrj 	/*
4157075Smrj 	 * If we get a bogus value, something is wrong with the H/W, fail to
4167075Smrj 	 * attach.
4177075Smrj 	 */
4187075Smrj 	if (state->is_num_channels == 0) {
4197075Smrj 		goto chipinitfail_numchan;
4207075Smrj 	}
4217075Smrj 
4226707Sbrutus 	state->is_maxxfer = (uint_t)ddi_get8(state->is_reg_handle,
4236707Sbrutus 	    &state->is_genregs[IOAT_XFERCAP]);
4246707Sbrutus 	state->is_chanoff = (uintptr_t)ddi_get16(state->is_reg_handle,
4256707Sbrutus 	    (uint16_t *)&state->is_genregs[IOAT_PERPORT_OFF]);
4266707Sbrutus 	state->is_cbver = (uint_t)ddi_get8(state->is_reg_handle,
4276707Sbrutus 	    &state->is_genregs[IOAT_CBVER]);
4286707Sbrutus 	state->is_intrdelay = (uint_t)ddi_get16(state->is_reg_handle,
4296707Sbrutus 	    (uint16_t *)&state->is_genregs[IOAT_INTRDELAY]);
4306707Sbrutus 	state->is_status = (uint_t)ddi_get16(state->is_reg_handle,
4316707Sbrutus 	    (uint16_t *)&state->is_genregs[IOAT_CSSTATUS]);
4326707Sbrutus 	state->is_capabilities = (uint_t)ddi_get32(state->is_reg_handle,
4336707Sbrutus 	    (uint32_t *)&state->is_genregs[IOAT_DMACAPABILITY]);
4346707Sbrutus 
4356707Sbrutus 	if (state->is_cbver & 0x10) {
4366707Sbrutus 		state->is_ver = IOAT_CBv1;
4376707Sbrutus 	} else if (state->is_cbver & 0x20) {
4386707Sbrutus 		state->is_ver = IOAT_CBv2;
4396707Sbrutus 	} else {
4406707Sbrutus 		goto chipinitfail_version;
4416707Sbrutus 	}
4426707Sbrutus 
4436707Sbrutus 	return (DDI_SUCCESS);
4446707Sbrutus 
4456707Sbrutus chipinitfail_version:
4467075Smrj chipinitfail_numchan:
4476707Sbrutus 	ddi_regs_map_free(&state->is_reg_handle);
4486707Sbrutus chipinitfail_regsmap:
4496707Sbrutus 	return (DDI_FAILURE);
4506707Sbrutus }
4516707Sbrutus 
4526707Sbrutus 
4536707Sbrutus /*
4546707Sbrutus  * ioat_chip_fini()
4556707Sbrutus  */
4566707Sbrutus static void
ioat_chip_fini(ioat_state_t * state)4576707Sbrutus ioat_chip_fini(ioat_state_t *state)
4586707Sbrutus {
4596707Sbrutus 	ddi_regs_map_free(&state->is_reg_handle);
4606707Sbrutus }
4616707Sbrutus 
4626707Sbrutus 
4636707Sbrutus /*
4646707Sbrutus  * ioat_drv_init()
4656707Sbrutus  */
4666707Sbrutus static int
ioat_drv_init(ioat_state_t * state)4676707Sbrutus ioat_drv_init(ioat_state_t *state)
4686707Sbrutus {
4696707Sbrutus 	ddi_acc_handle_t handle;
4706707Sbrutus 	int e;
4716707Sbrutus 
4726707Sbrutus 
4736707Sbrutus 	mutex_init(&state->is_mutex, NULL, MUTEX_DRIVER, NULL);
4746707Sbrutus 
4756707Sbrutus 	state->is_deviceinfo.di_dip = state->is_dip;
4766707Sbrutus 	state->is_deviceinfo.di_num_dma = state->is_num_channels;
4776707Sbrutus 	state->is_deviceinfo.di_maxxfer = state->is_maxxfer;
4786707Sbrutus 	state->is_deviceinfo.di_capabilities = state->is_capabilities;
4796707Sbrutus 	state->is_deviceinfo.di_cb = &ioat_cb;
4806707Sbrutus 
4816707Sbrutus 	e = pci_config_setup(state->is_dip, &handle);
4826707Sbrutus 	if (e != DDI_SUCCESS) {
4836707Sbrutus 		goto drvinitfail_config_setup;
4846707Sbrutus 	}
4856707Sbrutus 
4866707Sbrutus 	/* read in Vendor ID */
4876707Sbrutus 	state->is_deviceinfo.di_id = (uint64_t)pci_config_get16(handle, 0);
4886707Sbrutus 	state->is_deviceinfo.di_id = state->is_deviceinfo.di_id << 16;
4896707Sbrutus 
4906707Sbrutus 	/* read in Device ID */
4916707Sbrutus 	state->is_deviceinfo.di_id |= (uint64_t)pci_config_get16(handle, 2);
4926707Sbrutus 	state->is_deviceinfo.di_id = state->is_deviceinfo.di_id << 32;
4936707Sbrutus 
4946707Sbrutus 	/* Add in chipset version */
4956707Sbrutus 	state->is_deviceinfo.di_id |= (uint64_t)state->is_cbver;
4966707Sbrutus 	pci_config_teardown(&handle);
4976707Sbrutus 
4986707Sbrutus 	e = ddi_intr_hilevel(state->is_dip, 0);
4996707Sbrutus 	if (e != 0) {
5006707Sbrutus 		cmn_err(CE_WARN, "hilevel interrupt not supported\n");
5016707Sbrutus 		goto drvinitfail_hilevel;
5026707Sbrutus 	}
5036707Sbrutus 
5046707Sbrutus 	/* we don't support MSIs for v2 yet */
5056707Sbrutus 	e = ddi_add_intr(state->is_dip, 0, NULL, NULL, ioat_isr,
5066707Sbrutus 	    (caddr_t)state);
5076707Sbrutus 	if (e != DDI_SUCCESS) {
5086707Sbrutus 		goto drvinitfail_add_intr;
5096707Sbrutus 	}
5106707Sbrutus 
5116707Sbrutus 	e = ddi_get_iblock_cookie(state->is_dip, 0, &state->is_iblock_cookie);
5126707Sbrutus 	if (e != DDI_SUCCESS) {
5136707Sbrutus 		goto drvinitfail_iblock_cookie;
5146707Sbrutus 	}
5156707Sbrutus 
5166707Sbrutus 	e = ioat_channel_init(state);
5176707Sbrutus 	if (e != DDI_SUCCESS) {
5186707Sbrutus 		goto drvinitfail_channel_init;
5196707Sbrutus 	}
5206707Sbrutus 
5216707Sbrutus 	return (DDI_SUCCESS);
5226707Sbrutus 
5236707Sbrutus drvinitfail_channel_init:
5246707Sbrutus drvinitfail_iblock_cookie:
5256707Sbrutus 	ddi_remove_intr(state->is_dip, 0, state->is_iblock_cookie);
5266707Sbrutus drvinitfail_add_intr:
5276707Sbrutus drvinitfail_hilevel:
5286707Sbrutus drvinitfail_config_setup:
5296707Sbrutus 	mutex_destroy(&state->is_mutex);
5306707Sbrutus 
5316707Sbrutus 	return (DDI_FAILURE);
5326707Sbrutus }
5336707Sbrutus 
5346707Sbrutus 
5356707Sbrutus /*
5366707Sbrutus  * ioat_drv_fini()
5376707Sbrutus  */
5386707Sbrutus static void
ioat_drv_fini(ioat_state_t * state)5396707Sbrutus ioat_drv_fini(ioat_state_t *state)
5406707Sbrutus {
5416707Sbrutus 	ioat_channel_fini(state);
5426707Sbrutus 	ddi_remove_intr(state->is_dip, 0, state->is_iblock_cookie);
5436707Sbrutus 	mutex_destroy(&state->is_mutex);
5446707Sbrutus }
5456707Sbrutus 
5466707Sbrutus 
5476707Sbrutus /*
5486707Sbrutus  * ioat_unregister_complete()
5496707Sbrutus  */
5506707Sbrutus void
ioat_unregister_complete(void * device_private,int status)5516707Sbrutus ioat_unregister_complete(void *device_private, int status)
5526707Sbrutus {
5536707Sbrutus 	ioat_state_t *state;
5546707Sbrutus 
5556707Sbrutus 
5566707Sbrutus 	state = device_private;
5576707Sbrutus 
5586707Sbrutus 	if (status != DCOPY_SUCCESS) {
5596707Sbrutus 		cmn_err(CE_WARN, "asynchronous detach aborted\n");
5606707Sbrutus 		return;
5616707Sbrutus 	}
5626707Sbrutus 
5636707Sbrutus 	cmn_err(CE_CONT, "detach completing\n");
5646707Sbrutus 	ioat_detach_finish(state);
5656707Sbrutus }
5666707Sbrutus 
5676707Sbrutus 
5686707Sbrutus /*
5696707Sbrutus  * ioat_detach_finish()
5706707Sbrutus  */
5716707Sbrutus void
ioat_detach_finish(ioat_state_t * state)5726707Sbrutus ioat_detach_finish(ioat_state_t *state)
5736707Sbrutus {
5746707Sbrutus 	ioat_intr_disable(state);
5756707Sbrutus 	ddi_remove_minor_node(state->is_dip, NULL);
5766707Sbrutus 	ioat_drv_fini(state);
5776707Sbrutus 	ioat_chip_fini(state);
5786707Sbrutus 	(void) ddi_soft_state_free(ioat_statep, state->is_instance);
5796707Sbrutus }
5806707Sbrutus 
5816707Sbrutus 
5826707Sbrutus /*
5836707Sbrutus  * ioat_intr_enable()
5846707Sbrutus  */
5856707Sbrutus static void
ioat_intr_enable(ioat_state_t * state)5866707Sbrutus ioat_intr_enable(ioat_state_t *state)
5876707Sbrutus {
5886707Sbrutus 	uint32_t intr_status;
5896707Sbrutus 
5906707Sbrutus 
5916707Sbrutus 	/* Clear any pending interrupts */
5926707Sbrutus 	intr_status = ddi_get32(state->is_reg_handle,
5936707Sbrutus 	    (uint32_t *)&state->is_genregs[IOAT_ATTNSTATUS]);
5946707Sbrutus 	if (intr_status != 0) {
5956707Sbrutus 		ddi_put32(state->is_reg_handle,
5966707Sbrutus 		    (uint32_t *)&state->is_genregs[IOAT_ATTNSTATUS],
5976707Sbrutus 		    intr_status);
5986707Sbrutus 	}
5996707Sbrutus 
6006707Sbrutus 	/* Enable interrupts on the device */
6016707Sbrutus 	ddi_put8(state->is_reg_handle, &state->is_genregs[IOAT_INTRCTL],
6026707Sbrutus 	    IOAT_INTRCTL_MASTER_EN);
6036707Sbrutus }
6046707Sbrutus 
6056707Sbrutus 
6066707Sbrutus /*
6076707Sbrutus  * ioat_intr_disable()
6086707Sbrutus  */
6096707Sbrutus static void
ioat_intr_disable(ioat_state_t * state)6106707Sbrutus ioat_intr_disable(ioat_state_t *state)
6116707Sbrutus {
6126707Sbrutus 	/*
6136707Sbrutus 	 * disable interrupts on the device. A read of the interrupt control
6146707Sbrutus 	 * register clears the enable bit.
6156707Sbrutus 	 */
6166707Sbrutus 	(void) ddi_get8(state->is_reg_handle,
6176707Sbrutus 	    &state->is_genregs[IOAT_INTRCTL]);
6186707Sbrutus }
6196707Sbrutus 
6206707Sbrutus 
6216707Sbrutus /*
6226707Sbrutus  * ioat_isr()
6236707Sbrutus  */
6246707Sbrutus static uint_t
ioat_isr(caddr_t parm)6256707Sbrutus ioat_isr(caddr_t parm)
6266707Sbrutus {
6276707Sbrutus 	uint32_t intr_status;
6286707Sbrutus 	ioat_state_t *state;
6296707Sbrutus 	uint8_t intrctrl;
6306707Sbrutus 	uint32_t chan;
6316707Sbrutus 	uint_t r;
6326707Sbrutus 	int i;
6336707Sbrutus 
6346707Sbrutus 	state = (ioat_state_t *)parm;
6356707Sbrutus 
6366707Sbrutus 	intrctrl = ddi_get8(state->is_reg_handle,
6376707Sbrutus 	    &state->is_genregs[IOAT_INTRCTL]);
6386707Sbrutus 	/* master interrupt enable should always be set */
6396707Sbrutus 	ASSERT(intrctrl & IOAT_INTRCTL_MASTER_EN);
6406707Sbrutus 
6416707Sbrutus 	/* If the interrupt status bit isn't set, it's not ours */
6426707Sbrutus 	if (!(intrctrl & IOAT_INTRCTL_INTR_STAT)) {
6436707Sbrutus 		/* re-set master interrupt enable (since it clears on read) */
6446707Sbrutus 		ddi_put8(state->is_reg_handle,
6456707Sbrutus 		    &state->is_genregs[IOAT_INTRCTL], intrctrl);
6466707Sbrutus 		return (DDI_INTR_UNCLAIMED);
6476707Sbrutus 	}
6486707Sbrutus 
6496707Sbrutus 	/* see which channels generated the interrupt */
6506707Sbrutus 	intr_status = ddi_get32(state->is_reg_handle,
6516707Sbrutus 	    (uint32_t *)&state->is_genregs[IOAT_ATTNSTATUS]);
6526707Sbrutus 
6536707Sbrutus 	/* call the intr handler for the channels */
6546707Sbrutus 	r = DDI_INTR_UNCLAIMED;
6556707Sbrutus 	chan = 1;
6566707Sbrutus 	for (i = 0; i < state->is_num_channels; i++) {
6576707Sbrutus 		if (intr_status & chan) {
6586707Sbrutus 			ioat_channel_intr(&state->is_channel[i]);
6596707Sbrutus 			r = DDI_INTR_CLAIMED;
6606707Sbrutus 		}
6616707Sbrutus 		chan = chan << 1;
6626707Sbrutus 	}
6636707Sbrutus 
6646707Sbrutus 	/*
6656707Sbrutus 	 * if interrupt status bit was set, there should have been an
6666707Sbrutus 	 * attention status bit set too.
6676707Sbrutus 	 */
6686707Sbrutus 	ASSERT(r == DDI_INTR_CLAIMED);
6696707Sbrutus 
6706707Sbrutus 	/* re-set master interrupt enable (since it clears on read) */
6716707Sbrutus 	ddi_put8(state->is_reg_handle, &state->is_genregs[IOAT_INTRCTL],
6726707Sbrutus 	    intrctrl);
6736707Sbrutus 
6746707Sbrutus 	return (r);
6756707Sbrutus }
676*7656SSherry.Moore@Sun.COM 
677*7656SSherry.Moore@Sun.COM static int
ioat_quiesce(dev_info_t * dip)678*7656SSherry.Moore@Sun.COM ioat_quiesce(dev_info_t *dip)
679*7656SSherry.Moore@Sun.COM {
680*7656SSherry.Moore@Sun.COM 	ioat_state_t *state;
681*7656SSherry.Moore@Sun.COM 	int instance;
682*7656SSherry.Moore@Sun.COM 
683*7656SSherry.Moore@Sun.COM 	instance = ddi_get_instance(dip);
684*7656SSherry.Moore@Sun.COM 	state = ddi_get_soft_state(ioat_statep, instance);
685*7656SSherry.Moore@Sun.COM 	if (state == NULL) {
686*7656SSherry.Moore@Sun.COM 		return (DDI_FAILURE);
687*7656SSherry.Moore@Sun.COM 	}
688*7656SSherry.Moore@Sun.COM 
689*7656SSherry.Moore@Sun.COM 	ioat_intr_disable(state);
690*7656SSherry.Moore@Sun.COM 	ioat_channel_quiesce(state);
691*7656SSherry.Moore@Sun.COM 
692*7656SSherry.Moore@Sun.COM 	return (DDI_SUCCESS);
693*7656SSherry.Moore@Sun.COM }
694