xref: /illumos-gate/usr/src/uts/i86pc/io/ioat/ioat.c (revision 19397407)
18e50dcc9Sbrutus /*
28e50dcc9Sbrutus  * CDDL HEADER START
38e50dcc9Sbrutus  *
48e50dcc9Sbrutus  * The contents of this file are subject to the terms of the
58e50dcc9Sbrutus  * Common Development and Distribution License (the "License").
68e50dcc9Sbrutus  * You may not use this file except in compliance with the License.
78e50dcc9Sbrutus  *
88e50dcc9Sbrutus  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
98e50dcc9Sbrutus  * or http://www.opensolaris.org/os/licensing.
108e50dcc9Sbrutus  * See the License for the specific language governing permissions
118e50dcc9Sbrutus  * and limitations under the License.
128e50dcc9Sbrutus  *
138e50dcc9Sbrutus  * When distributing Covered Code, include this CDDL HEADER in each
148e50dcc9Sbrutus  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
158e50dcc9Sbrutus  * If applicable, add the following below this CDDL HEADER, with the
168e50dcc9Sbrutus  * fields enclosed by brackets "[]" replaced with your own identifying
178e50dcc9Sbrutus  * information: Portions Copyright [yyyy] [name of copyright owner]
188e50dcc9Sbrutus  *
198e50dcc9Sbrutus  * CDDL HEADER END
208e50dcc9Sbrutus  */
218e50dcc9Sbrutus 
228e50dcc9Sbrutus /*
238e50dcc9Sbrutus  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
248e50dcc9Sbrutus  * Use is subject to license terms.
258e50dcc9Sbrutus  */
268e50dcc9Sbrutus 
278e50dcc9Sbrutus #include <sys/errno.h>
288e50dcc9Sbrutus #include <sys/types.h>
298e50dcc9Sbrutus #include <sys/conf.h>
308e50dcc9Sbrutus #include <sys/kmem.h>
318e50dcc9Sbrutus #include <sys/ddi.h>
328e50dcc9Sbrutus #include <sys/stat.h>
338e50dcc9Sbrutus #include <sys/sunddi.h>
348e50dcc9Sbrutus #include <sys/file.h>
358e50dcc9Sbrutus #include <sys/open.h>
368e50dcc9Sbrutus #include <sys/modctl.h>
378e50dcc9Sbrutus #include <sys/ddi_impldefs.h>
388e50dcc9Sbrutus #include <sys/sysmacros.h>
398e50dcc9Sbrutus 
408e50dcc9Sbrutus #include <sys/ioat.h>
418e50dcc9Sbrutus 
428e50dcc9Sbrutus static int ioat_open(dev_t *devp, int flag, int otyp, cred_t *cred);
438e50dcc9Sbrutus static int ioat_close(dev_t devp, int flag, int otyp, cred_t *cred);
448e50dcc9Sbrutus static int ioat_attach(dev_info_t *devi, ddi_attach_cmd_t cmd);
458e50dcc9Sbrutus static int ioat_detach(dev_info_t *devi, ddi_detach_cmd_t cmd);
468e50dcc9Sbrutus static int ioat_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg,
478e50dcc9Sbrutus     void **result);
48*19397407SSherry Moore static int ioat_quiesce(dev_info_t *dip);
498e50dcc9Sbrutus 
508e50dcc9Sbrutus static 	struct cb_ops ioat_cb_ops = {
518e50dcc9Sbrutus 	ioat_open,		/* cb_open */
528e50dcc9Sbrutus 	ioat_close,		/* cb_close */
538e50dcc9Sbrutus 	nodev,			/* cb_strategy */
548e50dcc9Sbrutus 	nodev,			/* cb_print */
558e50dcc9Sbrutus 	nodev,			/* cb_dump */
568e50dcc9Sbrutus 	nodev,			/* cb_read */
578e50dcc9Sbrutus 	nodev,			/* cb_write */
588e50dcc9Sbrutus 	ioat_ioctl,		/* cb_ioctl */
598e50dcc9Sbrutus 	nodev,			/* cb_devmap */
608e50dcc9Sbrutus 	nodev,			/* cb_mmap */
618e50dcc9Sbrutus 	nodev,			/* cb_segmap */
628e50dcc9Sbrutus 	nochpoll,		/* cb_chpoll */
638e50dcc9Sbrutus 	ddi_prop_op,		/* cb_prop_op */
648e50dcc9Sbrutus 	NULL,			/* cb_stream */
658e50dcc9Sbrutus 	D_NEW | D_MP | D_64BIT | D_DEVMAP,	/* cb_flag */
668e50dcc9Sbrutus 	CB_REV
678e50dcc9Sbrutus };
688e50dcc9Sbrutus 
698e50dcc9Sbrutus static struct dev_ops ioat_dev_ops = {
708e50dcc9Sbrutus 	DEVO_REV,		/* devo_rev */
718e50dcc9Sbrutus 	0,			/* devo_refcnt */
728e50dcc9Sbrutus 	ioat_getinfo,		/* devo_getinfo */
738e50dcc9Sbrutus 	nulldev,		/* devo_identify */
748e50dcc9Sbrutus 	nulldev,		/* devo_probe */
758e50dcc9Sbrutus 	ioat_attach,		/* devo_attach */
768e50dcc9Sbrutus 	ioat_detach,		/* devo_detach */
778e50dcc9Sbrutus 	nodev,			/* devo_reset */
788e50dcc9Sbrutus 	&ioat_cb_ops,		/* devo_cb_ops */
798e50dcc9Sbrutus 	NULL,			/* devo_bus_ops */
80*19397407SSherry Moore 	NULL,			/* devo_power */
81*19397407SSherry Moore 	ioat_quiesce,		/* devo_quiesce */
828e50dcc9Sbrutus };
838e50dcc9Sbrutus 
848e50dcc9Sbrutus static struct modldrv ioat_modldrv = {
858e50dcc9Sbrutus 	&mod_driverops,		/* Type of module.  This one is a driver */
86613b2871SRichard Bean 	"ioat driver",		/* Name of the module. */
878e50dcc9Sbrutus 	&ioat_dev_ops,		/* driver ops */
888e50dcc9Sbrutus };
898e50dcc9Sbrutus 
908e50dcc9Sbrutus static struct modlinkage ioat_modlinkage = {
918e50dcc9Sbrutus 	MODREV_1,
928e50dcc9Sbrutus 	(void *) &ioat_modldrv,
938e50dcc9Sbrutus 	NULL
948e50dcc9Sbrutus };
958e50dcc9Sbrutus 
968e50dcc9Sbrutus 
978e50dcc9Sbrutus void *ioat_statep;
988e50dcc9Sbrutus 
998e50dcc9Sbrutus static int ioat_chip_init(ioat_state_t *state);
1008e50dcc9Sbrutus static void ioat_chip_fini(ioat_state_t *state);
1018e50dcc9Sbrutus static int ioat_drv_init(ioat_state_t *state);
1028e50dcc9Sbrutus static void ioat_drv_fini(ioat_state_t *state);
1038e50dcc9Sbrutus static uint_t ioat_isr(caddr_t parm);
1048e50dcc9Sbrutus static void ioat_intr_enable(ioat_state_t *state);
1058e50dcc9Sbrutus static void ioat_intr_disable(ioat_state_t *state);
1068e50dcc9Sbrutus void ioat_detach_finish(ioat_state_t *state);
1078e50dcc9Sbrutus 
1088e50dcc9Sbrutus 
1098e50dcc9Sbrutus ddi_device_acc_attr_t ioat_acc_attr = {
1108e50dcc9Sbrutus 	DDI_DEVICE_ATTR_V0,		/* devacc_attr_version */
1118e50dcc9Sbrutus 	DDI_NEVERSWAP_ACC,		/* devacc_attr_endian_flags */
1128e50dcc9Sbrutus 	DDI_STORECACHING_OK_ACC,	/* devacc_attr_dataorder */
1138e50dcc9Sbrutus 	DDI_DEFAULT_ACC			/* devacc_attr_access */
1148e50dcc9Sbrutus };
1158e50dcc9Sbrutus 
1168e50dcc9Sbrutus /* dcopy callback interface */
1178e50dcc9Sbrutus dcopy_device_cb_t ioat_cb = {
1188e50dcc9Sbrutus 	DCOPY_DEVICECB_V0,
1198e50dcc9Sbrutus 	0,		/* reserved */
1208e50dcc9Sbrutus 	ioat_channel_alloc,
1218e50dcc9Sbrutus 	ioat_channel_free,
1228e50dcc9Sbrutus 	ioat_cmd_alloc,
1238e50dcc9Sbrutus 	ioat_cmd_free,
1248e50dcc9Sbrutus 	ioat_cmd_post,
1258e50dcc9Sbrutus 	ioat_cmd_poll,
1268e50dcc9Sbrutus 	ioat_unregister_complete
1278e50dcc9Sbrutus };
1288e50dcc9Sbrutus 
1298e50dcc9Sbrutus /*
1308e50dcc9Sbrutus  * _init()
1318e50dcc9Sbrutus  */
1328e50dcc9Sbrutus int
_init(void)1338e50dcc9Sbrutus _init(void)
1348e50dcc9Sbrutus {
1358e50dcc9Sbrutus 	int e;
1368e50dcc9Sbrutus 
1378e50dcc9Sbrutus 	e = ddi_soft_state_init(&ioat_statep, sizeof (ioat_state_t), 1);
1388e50dcc9Sbrutus 	if (e != 0) {
1398e50dcc9Sbrutus 		return (e);
1408e50dcc9Sbrutus 	}
1418e50dcc9Sbrutus 
1428e50dcc9Sbrutus 	e = mod_install(&ioat_modlinkage);
1438e50dcc9Sbrutus 	if (e != 0) {
1448e50dcc9Sbrutus 		ddi_soft_state_fini(&ioat_statep);
1458e50dcc9Sbrutus 		return (e);
1468e50dcc9Sbrutus 	}
1478e50dcc9Sbrutus 
1488e50dcc9Sbrutus 	return (0);
1498e50dcc9Sbrutus }
1508e50dcc9Sbrutus 
1518e50dcc9Sbrutus /*
1528e50dcc9Sbrutus  * _info()
1538e50dcc9Sbrutus  */
1548e50dcc9Sbrutus int
_info(struct modinfo * modinfop)1558e50dcc9Sbrutus _info(struct modinfo *modinfop)
1568e50dcc9Sbrutus {
1578e50dcc9Sbrutus 	return (mod_info(&ioat_modlinkage, modinfop));
1588e50dcc9Sbrutus }
1598e50dcc9Sbrutus 
1608e50dcc9Sbrutus /*
1618e50dcc9Sbrutus  * _fini()
1628e50dcc9Sbrutus  */
1638e50dcc9Sbrutus int
_fini(void)1648e50dcc9Sbrutus _fini(void)
1658e50dcc9Sbrutus {
1668e50dcc9Sbrutus 	int e;
1678e50dcc9Sbrutus 
1688e50dcc9Sbrutus 	e = mod_remove(&ioat_modlinkage);
1698e50dcc9Sbrutus 	if (e != 0) {
1708e50dcc9Sbrutus 		return (e);
1718e50dcc9Sbrutus 	}
1728e50dcc9Sbrutus 
1738e50dcc9Sbrutus 	ddi_soft_state_fini(&ioat_statep);
1748e50dcc9Sbrutus 
1758e50dcc9Sbrutus 	return (0);
1768e50dcc9Sbrutus }
1778e50dcc9Sbrutus 
1788e50dcc9Sbrutus /*
1798e50dcc9Sbrutus  * ioat_attach()
1808e50dcc9Sbrutus  */
1818e50dcc9Sbrutus static int
ioat_attach(dev_info_t * dip,ddi_attach_cmd_t cmd)1828e50dcc9Sbrutus ioat_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
1838e50dcc9Sbrutus {
1848e50dcc9Sbrutus 	ioat_state_t *state;
1858e50dcc9Sbrutus 	int instance;
1868e50dcc9Sbrutus 	int e;
1878e50dcc9Sbrutus 
1888e50dcc9Sbrutus 
1898e50dcc9Sbrutus 	switch (cmd) {
1908e50dcc9Sbrutus 	case DDI_ATTACH:
1918e50dcc9Sbrutus 		break;
1928e50dcc9Sbrutus 
1938e50dcc9Sbrutus 	case DDI_RESUME:
1948e50dcc9Sbrutus 		instance = ddi_get_instance(dip);
1958e50dcc9Sbrutus 		state = ddi_get_soft_state(ioat_statep, instance);
1968e50dcc9Sbrutus 		if (state == NULL) {
1978e50dcc9Sbrutus 			return (DDI_FAILURE);
1988e50dcc9Sbrutus 		}
1998e50dcc9Sbrutus 		e = ioat_channel_resume(state);
2008e50dcc9Sbrutus 		if (e != DDI_SUCCESS) {
2018e50dcc9Sbrutus 			return (DDI_FAILURE);
2028e50dcc9Sbrutus 		}
2038e50dcc9Sbrutus 		ioat_intr_enable(state);
2048e50dcc9Sbrutus 		return (DDI_SUCCESS);
2058e50dcc9Sbrutus 
2068e50dcc9Sbrutus 	default:
2078e50dcc9Sbrutus 		return (DDI_FAILURE);
2088e50dcc9Sbrutus 	}
2098e50dcc9Sbrutus 
2108e50dcc9Sbrutus 	instance = ddi_get_instance(dip);
2118e50dcc9Sbrutus 	e = ddi_soft_state_zalloc(ioat_statep, instance);
2128e50dcc9Sbrutus 	if (e != DDI_SUCCESS) {
2138e50dcc9Sbrutus 		return (DDI_FAILURE);
2148e50dcc9Sbrutus 	}
2158e50dcc9Sbrutus 	state = ddi_get_soft_state(ioat_statep, instance);
2168e50dcc9Sbrutus 	if (state == NULL) {
2178e50dcc9Sbrutus 		goto attachfail_get_soft_state;
2188e50dcc9Sbrutus 	}
2198e50dcc9Sbrutus 
2208e50dcc9Sbrutus 	state->is_dip = dip;
2218e50dcc9Sbrutus 	state->is_instance = instance;
2228e50dcc9Sbrutus 
2238e50dcc9Sbrutus 	/* setup the registers, save away some device info */
2248e50dcc9Sbrutus 	e = ioat_chip_init(state);
2258e50dcc9Sbrutus 	if (e != DDI_SUCCESS) {
2268e50dcc9Sbrutus 		goto attachfail_chip_init;
2278e50dcc9Sbrutus 	}
2288e50dcc9Sbrutus 
2298e50dcc9Sbrutus 	/* initialize driver state, must be after chip init */
2308e50dcc9Sbrutus 	e = ioat_drv_init(state);
2318e50dcc9Sbrutus 	if (e != DDI_SUCCESS) {
2328e50dcc9Sbrutus 		goto attachfail_drv_init;
2338e50dcc9Sbrutus 	}
2348e50dcc9Sbrutus 
2358e50dcc9Sbrutus 	/* create the minor node (for the ioctl) */
2368e50dcc9Sbrutus 	e = ddi_create_minor_node(dip, "ioat", S_IFCHR, instance, DDI_PSEUDO,
2378e50dcc9Sbrutus 	    0);
2388e50dcc9Sbrutus 	if (e != DDI_SUCCESS) {
2398e50dcc9Sbrutus 		goto attachfail_minor_node;
2408e50dcc9Sbrutus 	}
2418e50dcc9Sbrutus 
2428e50dcc9Sbrutus 	/* Enable device interrupts */
2438e50dcc9Sbrutus 	ioat_intr_enable(state);
2448e50dcc9Sbrutus 
2458e50dcc9Sbrutus 	/* Report that driver was loaded */
2468e50dcc9Sbrutus 	ddi_report_dev(dip);
2478e50dcc9Sbrutus 
2488e50dcc9Sbrutus 	/* register with dcopy */
2498e50dcc9Sbrutus 	e = dcopy_device_register(state, &state->is_deviceinfo,
2508e50dcc9Sbrutus 	    &state->is_device_handle);
2518e50dcc9Sbrutus 	if (e != DCOPY_SUCCESS) {
2528e50dcc9Sbrutus 		goto attachfail_register;
2538e50dcc9Sbrutus 	}
2548e50dcc9Sbrutus 
2558e50dcc9Sbrutus 	return (DDI_SUCCESS);
2568e50dcc9Sbrutus 
2578e50dcc9Sbrutus attachfail_register:
2588e50dcc9Sbrutus 	ioat_intr_disable(state);
2598e50dcc9Sbrutus 	ddi_remove_minor_node(dip, NULL);
2608e50dcc9Sbrutus attachfail_minor_node:
2618e50dcc9Sbrutus 	ioat_drv_fini(state);
2628e50dcc9Sbrutus attachfail_drv_init:
2638e50dcc9Sbrutus 	ioat_chip_fini(state);
2648e50dcc9Sbrutus attachfail_chip_init:
2658e50dcc9Sbrutus attachfail_get_soft_state:
2668e50dcc9Sbrutus 	(void) ddi_soft_state_free(ioat_statep, instance);
2678e50dcc9Sbrutus 
2688e50dcc9Sbrutus 	return (DDI_FAILURE);
2698e50dcc9Sbrutus }
2708e50dcc9Sbrutus 
2718e50dcc9Sbrutus /*
2728e50dcc9Sbrutus  * ioat_detach()
2738e50dcc9Sbrutus  */
2748e50dcc9Sbrutus static int
ioat_detach(dev_info_t * dip,ddi_detach_cmd_t cmd)2758e50dcc9Sbrutus ioat_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
2768e50dcc9Sbrutus {
2778e50dcc9Sbrutus 	ioat_state_t *state;
2788e50dcc9Sbrutus 	int instance;
2798e50dcc9Sbrutus 	int e;
2808e50dcc9Sbrutus 
2818e50dcc9Sbrutus 
2828e50dcc9Sbrutus 	instance = ddi_get_instance(dip);
2838e50dcc9Sbrutus 	state = ddi_get_soft_state(ioat_statep, instance);
2848e50dcc9Sbrutus 	if (state == NULL) {
2858e50dcc9Sbrutus 		return (DDI_FAILURE);
2868e50dcc9Sbrutus 	}
2878e50dcc9Sbrutus 
2888e50dcc9Sbrutus 	switch (cmd) {
2898e50dcc9Sbrutus 	case DDI_DETACH:
2908e50dcc9Sbrutus 		break;
2918e50dcc9Sbrutus 
2928e50dcc9Sbrutus 	case DDI_SUSPEND:
2938e50dcc9Sbrutus 		ioat_channel_suspend(state);
2948e50dcc9Sbrutus 		return (DDI_SUCCESS);
2958e50dcc9Sbrutus 
2968e50dcc9Sbrutus 	default:
2978e50dcc9Sbrutus 		return (DDI_FAILURE);
2988e50dcc9Sbrutus 	}
2998e50dcc9Sbrutus 
3008e50dcc9Sbrutus 	/*
3018e50dcc9Sbrutus 	 * try to unregister from dcopy.  Since this driver doesn't follow the
3028e50dcc9Sbrutus 	 * traditional parent/child model, we may still be in use so we can't
3038e50dcc9Sbrutus 	 * detach yet.
3048e50dcc9Sbrutus 	 */
3058e50dcc9Sbrutus 	e = dcopy_device_unregister(&state->is_device_handle);
3068e50dcc9Sbrutus 	if (e != DCOPY_SUCCESS) {
3078e50dcc9Sbrutus 		if (e == DCOPY_PENDING) {
3088e50dcc9Sbrutus 			cmn_err(CE_NOTE, "device busy, performing asynchronous"
3098e50dcc9Sbrutus 			    " detach\n");
3108e50dcc9Sbrutus 		}
3118e50dcc9Sbrutus 		return (DDI_FAILURE);
3128e50dcc9Sbrutus 	}
3138e50dcc9Sbrutus 
3148e50dcc9Sbrutus 	ioat_detach_finish(state);
3158e50dcc9Sbrutus 
3168e50dcc9Sbrutus 	return (DDI_SUCCESS);
3178e50dcc9Sbrutus }
3188e50dcc9Sbrutus 
3198e50dcc9Sbrutus /*
3208e50dcc9Sbrutus  * ioat_getinfo()
3218e50dcc9Sbrutus  */
3228e50dcc9Sbrutus /*ARGSUSED*/
3238e50dcc9Sbrutus static int
ioat_getinfo(dev_info_t * dip,ddi_info_cmd_t cmd,void * arg,void ** result)3248e50dcc9Sbrutus ioat_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **result)
3258e50dcc9Sbrutus {
3268e50dcc9Sbrutus 	ioat_state_t *state;
3278e50dcc9Sbrutus 	int instance;
3288e50dcc9Sbrutus 	dev_t dev;
3298e50dcc9Sbrutus 	int e;
3308e50dcc9Sbrutus 
3318e50dcc9Sbrutus 
3328e50dcc9Sbrutus 	dev = (dev_t)arg;
3338e50dcc9Sbrutus 	instance = getminor(dev);
3348e50dcc9Sbrutus 
3358e50dcc9Sbrutus 	switch (cmd) {
3368e50dcc9Sbrutus 	case DDI_INFO_DEVT2DEVINFO:
3378e50dcc9Sbrutus 		state = ddi_get_soft_state(ioat_statep, instance);
3388e50dcc9Sbrutus 		if (state == NULL) {
3398e50dcc9Sbrutus 			return (DDI_FAILURE);
3408e50dcc9Sbrutus 		}
3418e50dcc9Sbrutus 		*result = (void *)state->is_dip;
3428e50dcc9Sbrutus 		e = DDI_SUCCESS;
3438e50dcc9Sbrutus 		break;
3448e50dcc9Sbrutus 
3458e50dcc9Sbrutus 	case DDI_INFO_DEVT2INSTANCE:
3468e50dcc9Sbrutus 		*result = (void *)(uintptr_t)instance;
3478e50dcc9Sbrutus 		e = DDI_SUCCESS;
3488e50dcc9Sbrutus 		break;
3498e50dcc9Sbrutus 
3508e50dcc9Sbrutus 	default:
3518e50dcc9Sbrutus 		e = DDI_FAILURE;
3528e50dcc9Sbrutus 		break;
3538e50dcc9Sbrutus 	}
3548e50dcc9Sbrutus 
3558e50dcc9Sbrutus 	return (e);
3568e50dcc9Sbrutus }
3578e50dcc9Sbrutus 
3588e50dcc9Sbrutus 
3598e50dcc9Sbrutus /*
3608e50dcc9Sbrutus  * ioat_open()
3618e50dcc9Sbrutus  */
3628e50dcc9Sbrutus /*ARGSUSED*/
3638e50dcc9Sbrutus static int
ioat_open(dev_t * devp,int flag,int otyp,cred_t * cred)3648e50dcc9Sbrutus ioat_open(dev_t *devp, int flag, int otyp, cred_t *cred)
3658e50dcc9Sbrutus {
3668e50dcc9Sbrutus 	ioat_state_t *state;
3678e50dcc9Sbrutus 	int instance;
3688e50dcc9Sbrutus 
3698e50dcc9Sbrutus 	instance = getminor(*devp);
3708e50dcc9Sbrutus 	state = ddi_get_soft_state(ioat_statep, instance);
3718e50dcc9Sbrutus 	if (state == NULL) {
3728e50dcc9Sbrutus 		return (ENXIO);
3738e50dcc9Sbrutus 	}
3748e50dcc9Sbrutus 
3758e50dcc9Sbrutus 	return (0);
3768e50dcc9Sbrutus }
3778e50dcc9Sbrutus 
3788e50dcc9Sbrutus 
3798e50dcc9Sbrutus /*
3808e50dcc9Sbrutus  * ioat_close()
3818e50dcc9Sbrutus  */
3828e50dcc9Sbrutus /*ARGSUSED*/
3838e50dcc9Sbrutus static int
ioat_close(dev_t devp,int flag,int otyp,cred_t * cred)3848e50dcc9Sbrutus ioat_close(dev_t devp, int flag, int otyp, cred_t *cred)
3858e50dcc9Sbrutus {
3868e50dcc9Sbrutus 	return (0);
3878e50dcc9Sbrutus }
3888e50dcc9Sbrutus 
3898e50dcc9Sbrutus 
3908e50dcc9Sbrutus /*
3918e50dcc9Sbrutus  * ioat_chip_init()
3928e50dcc9Sbrutus  */
3938e50dcc9Sbrutus static int
ioat_chip_init(ioat_state_t * state)3948e50dcc9Sbrutus ioat_chip_init(ioat_state_t *state)
3958e50dcc9Sbrutus {
3968e50dcc9Sbrutus 	ddi_device_acc_attr_t attr;
3978e50dcc9Sbrutus 	int e;
3988e50dcc9Sbrutus 
3998e50dcc9Sbrutus 
4008e50dcc9Sbrutus 	attr.devacc_attr_version = DDI_DEVICE_ATTR_V0;
4018e50dcc9Sbrutus 	attr.devacc_attr_endian_flags = DDI_NEVERSWAP_ACC;
4028e50dcc9Sbrutus 	attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC;
4038e50dcc9Sbrutus 
4048e50dcc9Sbrutus 	e =  ddi_regs_map_setup(state->is_dip, 1, (caddr_t *)&state->is_genregs,
4058e50dcc9Sbrutus 	    0, 0, &attr, &state->is_reg_handle);
4068e50dcc9Sbrutus 	if (e != DDI_SUCCESS) {
4078e50dcc9Sbrutus 		goto chipinitfail_regsmap;
4088e50dcc9Sbrutus 	}
4098e50dcc9Sbrutus 
4108e50dcc9Sbrutus 	/* save away ioat chip info */
4118e50dcc9Sbrutus 	state->is_num_channels = (uint_t)ddi_get8(state->is_reg_handle,
4128e50dcc9Sbrutus 	    &state->is_genregs[IOAT_CHANCNT]);
413e6beb20cSmrj 
414e6beb20cSmrj 	/*
415e6beb20cSmrj 	 * If we get a bogus value, something is wrong with the H/W, fail to
416e6beb20cSmrj 	 * attach.
417e6beb20cSmrj 	 */
418e6beb20cSmrj 	if (state->is_num_channels == 0) {
419e6beb20cSmrj 		goto chipinitfail_numchan;
420e6beb20cSmrj 	}
421e6beb20cSmrj 
4228e50dcc9Sbrutus 	state->is_maxxfer = (uint_t)ddi_get8(state->is_reg_handle,
4238e50dcc9Sbrutus 	    &state->is_genregs[IOAT_XFERCAP]);
4248e50dcc9Sbrutus 	state->is_chanoff = (uintptr_t)ddi_get16(state->is_reg_handle,
4258e50dcc9Sbrutus 	    (uint16_t *)&state->is_genregs[IOAT_PERPORT_OFF]);
4268e50dcc9Sbrutus 	state->is_cbver = (uint_t)ddi_get8(state->is_reg_handle,
4278e50dcc9Sbrutus 	    &state->is_genregs[IOAT_CBVER]);
4288e50dcc9Sbrutus 	state->is_intrdelay = (uint_t)ddi_get16(state->is_reg_handle,
4298e50dcc9Sbrutus 	    (uint16_t *)&state->is_genregs[IOAT_INTRDELAY]);
4308e50dcc9Sbrutus 	state->is_status = (uint_t)ddi_get16(state->is_reg_handle,
4318e50dcc9Sbrutus 	    (uint16_t *)&state->is_genregs[IOAT_CSSTATUS]);
4328e50dcc9Sbrutus 	state->is_capabilities = (uint_t)ddi_get32(state->is_reg_handle,
4338e50dcc9Sbrutus 	    (uint32_t *)&state->is_genregs[IOAT_DMACAPABILITY]);
4348e50dcc9Sbrutus 
4358e50dcc9Sbrutus 	if (state->is_cbver & 0x10) {
4368e50dcc9Sbrutus 		state->is_ver = IOAT_CBv1;
4378e50dcc9Sbrutus 	} else if (state->is_cbver & 0x20) {
4388e50dcc9Sbrutus 		state->is_ver = IOAT_CBv2;
4398e50dcc9Sbrutus 	} else {
4408e50dcc9Sbrutus 		goto chipinitfail_version;
4418e50dcc9Sbrutus 	}
4428e50dcc9Sbrutus 
4438e50dcc9Sbrutus 	return (DDI_SUCCESS);
4448e50dcc9Sbrutus 
4458e50dcc9Sbrutus chipinitfail_version:
446e6beb20cSmrj chipinitfail_numchan:
4478e50dcc9Sbrutus 	ddi_regs_map_free(&state->is_reg_handle);
4488e50dcc9Sbrutus chipinitfail_regsmap:
4498e50dcc9Sbrutus 	return (DDI_FAILURE);
4508e50dcc9Sbrutus }
4518e50dcc9Sbrutus 
4528e50dcc9Sbrutus 
4538e50dcc9Sbrutus /*
4548e50dcc9Sbrutus  * ioat_chip_fini()
4558e50dcc9Sbrutus  */
4568e50dcc9Sbrutus static void
ioat_chip_fini(ioat_state_t * state)4578e50dcc9Sbrutus ioat_chip_fini(ioat_state_t *state)
4588e50dcc9Sbrutus {
4598e50dcc9Sbrutus 	ddi_regs_map_free(&state->is_reg_handle);
4608e50dcc9Sbrutus }
4618e50dcc9Sbrutus 
4628e50dcc9Sbrutus 
4638e50dcc9Sbrutus /*
4648e50dcc9Sbrutus  * ioat_drv_init()
4658e50dcc9Sbrutus  */
4668e50dcc9Sbrutus static int
ioat_drv_init(ioat_state_t * state)4678e50dcc9Sbrutus ioat_drv_init(ioat_state_t *state)
4688e50dcc9Sbrutus {
4698e50dcc9Sbrutus 	ddi_acc_handle_t handle;
4708e50dcc9Sbrutus 	int e;
4718e50dcc9Sbrutus 
4728e50dcc9Sbrutus 
4738e50dcc9Sbrutus 	mutex_init(&state->is_mutex, NULL, MUTEX_DRIVER, NULL);
4748e50dcc9Sbrutus 
4758e50dcc9Sbrutus 	state->is_deviceinfo.di_dip = state->is_dip;
4768e50dcc9Sbrutus 	state->is_deviceinfo.di_num_dma = state->is_num_channels;
4778e50dcc9Sbrutus 	state->is_deviceinfo.di_maxxfer = state->is_maxxfer;
4788e50dcc9Sbrutus 	state->is_deviceinfo.di_capabilities = state->is_capabilities;
4798e50dcc9Sbrutus 	state->is_deviceinfo.di_cb = &ioat_cb;
4808e50dcc9Sbrutus 
4818e50dcc9Sbrutus 	e = pci_config_setup(state->is_dip, &handle);
4828e50dcc9Sbrutus 	if (e != DDI_SUCCESS) {
4838e50dcc9Sbrutus 		goto drvinitfail_config_setup;
4848e50dcc9Sbrutus 	}
4858e50dcc9Sbrutus 
4868e50dcc9Sbrutus 	/* read in Vendor ID */
4878e50dcc9Sbrutus 	state->is_deviceinfo.di_id = (uint64_t)pci_config_get16(handle, 0);
4888e50dcc9Sbrutus 	state->is_deviceinfo.di_id = state->is_deviceinfo.di_id << 16;
4898e50dcc9Sbrutus 
4908e50dcc9Sbrutus 	/* read in Device ID */
4918e50dcc9Sbrutus 	state->is_deviceinfo.di_id |= (uint64_t)pci_config_get16(handle, 2);
4928e50dcc9Sbrutus 	state->is_deviceinfo.di_id = state->is_deviceinfo.di_id << 32;
4938e50dcc9Sbrutus 
4948e50dcc9Sbrutus 	/* Add in chipset version */
4958e50dcc9Sbrutus 	state->is_deviceinfo.di_id |= (uint64_t)state->is_cbver;
4968e50dcc9Sbrutus 	pci_config_teardown(&handle);
4978e50dcc9Sbrutus 
4988e50dcc9Sbrutus 	e = ddi_intr_hilevel(state->is_dip, 0);
4998e50dcc9Sbrutus 	if (e != 0) {
5008e50dcc9Sbrutus 		cmn_err(CE_WARN, "hilevel interrupt not supported\n");
5018e50dcc9Sbrutus 		goto drvinitfail_hilevel;
5028e50dcc9Sbrutus 	}
5038e50dcc9Sbrutus 
5048e50dcc9Sbrutus 	/* we don't support MSIs for v2 yet */
5058e50dcc9Sbrutus 	e = ddi_add_intr(state->is_dip, 0, NULL, NULL, ioat_isr,
5068e50dcc9Sbrutus 	    (caddr_t)state);
5078e50dcc9Sbrutus 	if (e != DDI_SUCCESS) {
5088e50dcc9Sbrutus 		goto drvinitfail_add_intr;
5098e50dcc9Sbrutus 	}
5108e50dcc9Sbrutus 
5118e50dcc9Sbrutus 	e = ddi_get_iblock_cookie(state->is_dip, 0, &state->is_iblock_cookie);
5128e50dcc9Sbrutus 	if (e != DDI_SUCCESS) {
5138e50dcc9Sbrutus 		goto drvinitfail_iblock_cookie;
5148e50dcc9Sbrutus 	}
5158e50dcc9Sbrutus 
5168e50dcc9Sbrutus 	e = ioat_channel_init(state);
5178e50dcc9Sbrutus 	if (e != DDI_SUCCESS) {
5188e50dcc9Sbrutus 		goto drvinitfail_channel_init;
5198e50dcc9Sbrutus 	}
5208e50dcc9Sbrutus 
5218e50dcc9Sbrutus 	return (DDI_SUCCESS);
5228e50dcc9Sbrutus 
5238e50dcc9Sbrutus drvinitfail_channel_init:
5248e50dcc9Sbrutus drvinitfail_iblock_cookie:
5258e50dcc9Sbrutus 	ddi_remove_intr(state->is_dip, 0, state->is_iblock_cookie);
5268e50dcc9Sbrutus drvinitfail_add_intr:
5278e50dcc9Sbrutus drvinitfail_hilevel:
5288e50dcc9Sbrutus drvinitfail_config_setup:
5298e50dcc9Sbrutus 	mutex_destroy(&state->is_mutex);
5308e50dcc9Sbrutus 
5318e50dcc9Sbrutus 	return (DDI_FAILURE);
5328e50dcc9Sbrutus }
5338e50dcc9Sbrutus 
5348e50dcc9Sbrutus 
5358e50dcc9Sbrutus /*
5368e50dcc9Sbrutus  * ioat_drv_fini()
5378e50dcc9Sbrutus  */
5388e50dcc9Sbrutus static void
ioat_drv_fini(ioat_state_t * state)5398e50dcc9Sbrutus ioat_drv_fini(ioat_state_t *state)
5408e50dcc9Sbrutus {
5418e50dcc9Sbrutus 	ioat_channel_fini(state);
5428e50dcc9Sbrutus 	ddi_remove_intr(state->is_dip, 0, state->is_iblock_cookie);
5438e50dcc9Sbrutus 	mutex_destroy(&state->is_mutex);
5448e50dcc9Sbrutus }
5458e50dcc9Sbrutus 
5468e50dcc9Sbrutus 
5478e50dcc9Sbrutus /*
5488e50dcc9Sbrutus  * ioat_unregister_complete()
5498e50dcc9Sbrutus  */
5508e50dcc9Sbrutus void
ioat_unregister_complete(void * device_private,int status)5518e50dcc9Sbrutus ioat_unregister_complete(void *device_private, int status)
5528e50dcc9Sbrutus {
5538e50dcc9Sbrutus 	ioat_state_t *state;
5548e50dcc9Sbrutus 
5558e50dcc9Sbrutus 
5568e50dcc9Sbrutus 	state = device_private;
5578e50dcc9Sbrutus 
5588e50dcc9Sbrutus 	if (status != DCOPY_SUCCESS) {
5598e50dcc9Sbrutus 		cmn_err(CE_WARN, "asynchronous detach aborted\n");
5608e50dcc9Sbrutus 		return;
5618e50dcc9Sbrutus 	}
5628e50dcc9Sbrutus 
5638e50dcc9Sbrutus 	cmn_err(CE_CONT, "detach completing\n");
5648e50dcc9Sbrutus 	ioat_detach_finish(state);
5658e50dcc9Sbrutus }
5668e50dcc9Sbrutus 
5678e50dcc9Sbrutus 
5688e50dcc9Sbrutus /*
5698e50dcc9Sbrutus  * ioat_detach_finish()
5708e50dcc9Sbrutus  */
5718e50dcc9Sbrutus void
ioat_detach_finish(ioat_state_t * state)5728e50dcc9Sbrutus ioat_detach_finish(ioat_state_t *state)
5738e50dcc9Sbrutus {
5748e50dcc9Sbrutus 	ioat_intr_disable(state);
5758e50dcc9Sbrutus 	ddi_remove_minor_node(state->is_dip, NULL);
5768e50dcc9Sbrutus 	ioat_drv_fini(state);
5778e50dcc9Sbrutus 	ioat_chip_fini(state);
5788e50dcc9Sbrutus 	(void) ddi_soft_state_free(ioat_statep, state->is_instance);
5798e50dcc9Sbrutus }
5808e50dcc9Sbrutus 
5818e50dcc9Sbrutus 
5828e50dcc9Sbrutus /*
5838e50dcc9Sbrutus  * ioat_intr_enable()
5848e50dcc9Sbrutus  */
5858e50dcc9Sbrutus static void
ioat_intr_enable(ioat_state_t * state)5868e50dcc9Sbrutus ioat_intr_enable(ioat_state_t *state)
5878e50dcc9Sbrutus {
5888e50dcc9Sbrutus 	uint32_t intr_status;
5898e50dcc9Sbrutus 
5908e50dcc9Sbrutus 
5918e50dcc9Sbrutus 	/* Clear any pending interrupts */
5928e50dcc9Sbrutus 	intr_status = ddi_get32(state->is_reg_handle,
5938e50dcc9Sbrutus 	    (uint32_t *)&state->is_genregs[IOAT_ATTNSTATUS]);
5948e50dcc9Sbrutus 	if (intr_status != 0) {
5958e50dcc9Sbrutus 		ddi_put32(state->is_reg_handle,
5968e50dcc9Sbrutus 		    (uint32_t *)&state->is_genregs[IOAT_ATTNSTATUS],
5978e50dcc9Sbrutus 		    intr_status);
5988e50dcc9Sbrutus 	}
5998e50dcc9Sbrutus 
6008e50dcc9Sbrutus 	/* Enable interrupts on the device */
6018e50dcc9Sbrutus 	ddi_put8(state->is_reg_handle, &state->is_genregs[IOAT_INTRCTL],
6028e50dcc9Sbrutus 	    IOAT_INTRCTL_MASTER_EN);
6038e50dcc9Sbrutus }
6048e50dcc9Sbrutus 
6058e50dcc9Sbrutus 
6068e50dcc9Sbrutus /*
6078e50dcc9Sbrutus  * ioat_intr_disable()
6088e50dcc9Sbrutus  */
6098e50dcc9Sbrutus static void
ioat_intr_disable(ioat_state_t * state)6108e50dcc9Sbrutus ioat_intr_disable(ioat_state_t *state)
6118e50dcc9Sbrutus {
6128e50dcc9Sbrutus 	/*
6138e50dcc9Sbrutus 	 * disable interrupts on the device. A read of the interrupt control
6148e50dcc9Sbrutus 	 * register clears the enable bit.
6158e50dcc9Sbrutus 	 */
6168e50dcc9Sbrutus 	(void) ddi_get8(state->is_reg_handle,
6178e50dcc9Sbrutus 	    &state->is_genregs[IOAT_INTRCTL]);
6188e50dcc9Sbrutus }
6198e50dcc9Sbrutus 
6208e50dcc9Sbrutus 
6218e50dcc9Sbrutus /*
6228e50dcc9Sbrutus  * ioat_isr()
6238e50dcc9Sbrutus  */
6248e50dcc9Sbrutus static uint_t
ioat_isr(caddr_t parm)6258e50dcc9Sbrutus ioat_isr(caddr_t parm)
6268e50dcc9Sbrutus {
6278e50dcc9Sbrutus 	uint32_t intr_status;
6288e50dcc9Sbrutus 	ioat_state_t *state;
6298e50dcc9Sbrutus 	uint8_t intrctrl;
6308e50dcc9Sbrutus 	uint32_t chan;
6318e50dcc9Sbrutus 	uint_t r;
6328e50dcc9Sbrutus 	int i;
6338e50dcc9Sbrutus 
6348e50dcc9Sbrutus 	state = (ioat_state_t *)parm;
6358e50dcc9Sbrutus 
6368e50dcc9Sbrutus 	intrctrl = ddi_get8(state->is_reg_handle,
6378e50dcc9Sbrutus 	    &state->is_genregs[IOAT_INTRCTL]);
6388e50dcc9Sbrutus 	/* master interrupt enable should always be set */
6398e50dcc9Sbrutus 	ASSERT(intrctrl & IOAT_INTRCTL_MASTER_EN);
6408e50dcc9Sbrutus 
6418e50dcc9Sbrutus 	/* If the interrupt status bit isn't set, it's not ours */
6428e50dcc9Sbrutus 	if (!(intrctrl & IOAT_INTRCTL_INTR_STAT)) {
6438e50dcc9Sbrutus 		/* re-set master interrupt enable (since it clears on read) */
6448e50dcc9Sbrutus 		ddi_put8(state->is_reg_handle,
6458e50dcc9Sbrutus 		    &state->is_genregs[IOAT_INTRCTL], intrctrl);
6468e50dcc9Sbrutus 		return (DDI_INTR_UNCLAIMED);
6478e50dcc9Sbrutus 	}
6488e50dcc9Sbrutus 
6498e50dcc9Sbrutus 	/* see which channels generated the interrupt */
6508e50dcc9Sbrutus 	intr_status = ddi_get32(state->is_reg_handle,
6518e50dcc9Sbrutus 	    (uint32_t *)&state->is_genregs[IOAT_ATTNSTATUS]);
6528e50dcc9Sbrutus 
6538e50dcc9Sbrutus 	/* call the intr handler for the channels */
6548e50dcc9Sbrutus 	r = DDI_INTR_UNCLAIMED;
6558e50dcc9Sbrutus 	chan = 1;
6568e50dcc9Sbrutus 	for (i = 0; i < state->is_num_channels; i++) {
6578e50dcc9Sbrutus 		if (intr_status & chan) {
6588e50dcc9Sbrutus 			ioat_channel_intr(&state->is_channel[i]);
6598e50dcc9Sbrutus 			r = DDI_INTR_CLAIMED;
6608e50dcc9Sbrutus 		}
6618e50dcc9Sbrutus 		chan = chan << 1;
6628e50dcc9Sbrutus 	}
6638e50dcc9Sbrutus 
6648e50dcc9Sbrutus 	/*
6658e50dcc9Sbrutus 	 * if interrupt status bit was set, there should have been an
6668e50dcc9Sbrutus 	 * attention status bit set too.
6678e50dcc9Sbrutus 	 */
6688e50dcc9Sbrutus 	ASSERT(r == DDI_INTR_CLAIMED);
6698e50dcc9Sbrutus 
6708e50dcc9Sbrutus 	/* re-set master interrupt enable (since it clears on read) */
6718e50dcc9Sbrutus 	ddi_put8(state->is_reg_handle, &state->is_genregs[IOAT_INTRCTL],
6728e50dcc9Sbrutus 	    intrctrl);
6738e50dcc9Sbrutus 
6748e50dcc9Sbrutus 	return (r);
6758e50dcc9Sbrutus }
676*19397407SSherry Moore 
677*19397407SSherry Moore static int
ioat_quiesce(dev_info_t * dip)678*19397407SSherry Moore ioat_quiesce(dev_info_t *dip)
679*19397407SSherry Moore {
680*19397407SSherry Moore 	ioat_state_t *state;
681*19397407SSherry Moore 	int instance;
682*19397407SSherry Moore 
683*19397407SSherry Moore 	instance = ddi_get_instance(dip);
684*19397407SSherry Moore 	state = ddi_get_soft_state(ioat_statep, instance);
685*19397407SSherry Moore 	if (state == NULL) {
686*19397407SSherry Moore 		return (DDI_FAILURE);
687*19397407SSherry Moore 	}
688*19397407SSherry Moore 
689*19397407SSherry Moore 	ioat_intr_disable(state);
690*19397407SSherry Moore 	ioat_channel_quiesce(state);
691*19397407SSherry Moore 
692*19397407SSherry Moore 	return (DDI_SUCCESS);
693*19397407SSherry Moore }
694