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