xref: /titanic_52/usr/src/uts/i86pc/io/ioat/ioat.c (revision 193974072f41a843678abf5f61979c748687e66b)
117169044Sbrutus /*
217169044Sbrutus  * CDDL HEADER START
317169044Sbrutus  *
417169044Sbrutus  * The contents of this file are subject to the terms of the
517169044Sbrutus  * Common Development and Distribution License (the "License").
617169044Sbrutus  * You may not use this file except in compliance with the License.
717169044Sbrutus  *
817169044Sbrutus  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
917169044Sbrutus  * or http://www.opensolaris.org/os/licensing.
1017169044Sbrutus  * See the License for the specific language governing permissions
1117169044Sbrutus  * and limitations under the License.
1217169044Sbrutus  *
1317169044Sbrutus  * When distributing Covered Code, include this CDDL HEADER in each
1417169044Sbrutus  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
1517169044Sbrutus  * If applicable, add the following below this CDDL HEADER, with the
1617169044Sbrutus  * fields enclosed by brackets "[]" replaced with your own identifying
1717169044Sbrutus  * information: Portions Copyright [yyyy] [name of copyright owner]
1817169044Sbrutus  *
1917169044Sbrutus  * CDDL HEADER END
2017169044Sbrutus  */
2117169044Sbrutus 
2217169044Sbrutus /*
2317169044Sbrutus  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
2417169044Sbrutus  * Use is subject to license terms.
2517169044Sbrutus  */
2617169044Sbrutus 
2717169044Sbrutus #include <sys/errno.h>
2817169044Sbrutus #include <sys/types.h>
2917169044Sbrutus #include <sys/conf.h>
3017169044Sbrutus #include <sys/kmem.h>
3117169044Sbrutus #include <sys/ddi.h>
3217169044Sbrutus #include <sys/stat.h>
3317169044Sbrutus #include <sys/sunddi.h>
3417169044Sbrutus #include <sys/file.h>
3517169044Sbrutus #include <sys/open.h>
3617169044Sbrutus #include <sys/modctl.h>
3717169044Sbrutus #include <sys/ddi_impldefs.h>
3817169044Sbrutus #include <sys/sysmacros.h>
3917169044Sbrutus 
4017169044Sbrutus #include <sys/ioat.h>
4117169044Sbrutus 
4217169044Sbrutus static int ioat_open(dev_t *devp, int flag, int otyp, cred_t *cred);
4317169044Sbrutus static int ioat_close(dev_t devp, int flag, int otyp, cred_t *cred);
4417169044Sbrutus static int ioat_attach(dev_info_t *devi, ddi_attach_cmd_t cmd);
4517169044Sbrutus static int ioat_detach(dev_info_t *devi, ddi_detach_cmd_t cmd);
4617169044Sbrutus static int ioat_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg,
4717169044Sbrutus     void **result);
48*19397407SSherry Moore static int ioat_quiesce(dev_info_t *dip);
4917169044Sbrutus 
5017169044Sbrutus static 	struct cb_ops ioat_cb_ops = {
5117169044Sbrutus 	ioat_open,		/* cb_open */
5217169044Sbrutus 	ioat_close,		/* cb_close */
5317169044Sbrutus 	nodev,			/* cb_strategy */
5417169044Sbrutus 	nodev,			/* cb_print */
5517169044Sbrutus 	nodev,			/* cb_dump */
5617169044Sbrutus 	nodev,			/* cb_read */
5717169044Sbrutus 	nodev,			/* cb_write */
5817169044Sbrutus 	ioat_ioctl,		/* cb_ioctl */
5917169044Sbrutus 	nodev,			/* cb_devmap */
6017169044Sbrutus 	nodev,			/* cb_mmap */
6117169044Sbrutus 	nodev,			/* cb_segmap */
6217169044Sbrutus 	nochpoll,		/* cb_chpoll */
6317169044Sbrutus 	ddi_prop_op,		/* cb_prop_op */
6417169044Sbrutus 	NULL,			/* cb_stream */
6517169044Sbrutus 	D_NEW | D_MP | D_64BIT | D_DEVMAP,	/* cb_flag */
6617169044Sbrutus 	CB_REV
6717169044Sbrutus };
6817169044Sbrutus 
6917169044Sbrutus static struct dev_ops ioat_dev_ops = {
7017169044Sbrutus 	DEVO_REV,		/* devo_rev */
7117169044Sbrutus 	0,			/* devo_refcnt */
7217169044Sbrutus 	ioat_getinfo,		/* devo_getinfo */
7317169044Sbrutus 	nulldev,		/* devo_identify */
7417169044Sbrutus 	nulldev,		/* devo_probe */
7517169044Sbrutus 	ioat_attach,		/* devo_attach */
7617169044Sbrutus 	ioat_detach,		/* devo_detach */
7717169044Sbrutus 	nodev,			/* devo_reset */
7817169044Sbrutus 	&ioat_cb_ops,		/* devo_cb_ops */
7917169044Sbrutus 	NULL,			/* devo_bus_ops */
80*19397407SSherry Moore 	NULL,			/* devo_power */
81*19397407SSherry Moore 	ioat_quiesce,		/* devo_quiesce */
8217169044Sbrutus };
8317169044Sbrutus 
8417169044Sbrutus static struct modldrv ioat_modldrv = {
8517169044Sbrutus 	&mod_driverops,		/* Type of module.  This one is a driver */
86613b2871SRichard Bean 	"ioat driver",		/* Name of the module. */
8717169044Sbrutus 	&ioat_dev_ops,		/* driver ops */
8817169044Sbrutus };
8917169044Sbrutus 
9017169044Sbrutus static struct modlinkage ioat_modlinkage = {
9117169044Sbrutus 	MODREV_1,
9217169044Sbrutus 	(void *) &ioat_modldrv,
9317169044Sbrutus 	NULL
9417169044Sbrutus };
9517169044Sbrutus 
9617169044Sbrutus 
9717169044Sbrutus void *ioat_statep;
9817169044Sbrutus 
9917169044Sbrutus static int ioat_chip_init(ioat_state_t *state);
10017169044Sbrutus static void ioat_chip_fini(ioat_state_t *state);
10117169044Sbrutus static int ioat_drv_init(ioat_state_t *state);
10217169044Sbrutus static void ioat_drv_fini(ioat_state_t *state);
10317169044Sbrutus static uint_t ioat_isr(caddr_t parm);
10417169044Sbrutus static void ioat_intr_enable(ioat_state_t *state);
10517169044Sbrutus static void ioat_intr_disable(ioat_state_t *state);
10617169044Sbrutus void ioat_detach_finish(ioat_state_t *state);
10717169044Sbrutus 
10817169044Sbrutus 
10917169044Sbrutus ddi_device_acc_attr_t ioat_acc_attr = {
11017169044Sbrutus 	DDI_DEVICE_ATTR_V0,		/* devacc_attr_version */
11117169044Sbrutus 	DDI_NEVERSWAP_ACC,		/* devacc_attr_endian_flags */
11217169044Sbrutus 	DDI_STORECACHING_OK_ACC,	/* devacc_attr_dataorder */
11317169044Sbrutus 	DDI_DEFAULT_ACC			/* devacc_attr_access */
11417169044Sbrutus };
11517169044Sbrutus 
11617169044Sbrutus /* dcopy callback interface */
11717169044Sbrutus dcopy_device_cb_t ioat_cb = {
11817169044Sbrutus 	DCOPY_DEVICECB_V0,
11917169044Sbrutus 	0,		/* reserved */
12017169044Sbrutus 	ioat_channel_alloc,
12117169044Sbrutus 	ioat_channel_free,
12217169044Sbrutus 	ioat_cmd_alloc,
12317169044Sbrutus 	ioat_cmd_free,
12417169044Sbrutus 	ioat_cmd_post,
12517169044Sbrutus 	ioat_cmd_poll,
12617169044Sbrutus 	ioat_unregister_complete
12717169044Sbrutus };
12817169044Sbrutus 
12917169044Sbrutus /*
13017169044Sbrutus  * _init()
13117169044Sbrutus  */
13217169044Sbrutus int
13317169044Sbrutus _init(void)
13417169044Sbrutus {
13517169044Sbrutus 	int e;
13617169044Sbrutus 
13717169044Sbrutus 	e = ddi_soft_state_init(&ioat_statep, sizeof (ioat_state_t), 1);
13817169044Sbrutus 	if (e != 0) {
13917169044Sbrutus 		return (e);
14017169044Sbrutus 	}
14117169044Sbrutus 
14217169044Sbrutus 	e = mod_install(&ioat_modlinkage);
14317169044Sbrutus 	if (e != 0) {
14417169044Sbrutus 		ddi_soft_state_fini(&ioat_statep);
14517169044Sbrutus 		return (e);
14617169044Sbrutus 	}
14717169044Sbrutus 
14817169044Sbrutus 	return (0);
14917169044Sbrutus }
15017169044Sbrutus 
15117169044Sbrutus /*
15217169044Sbrutus  * _info()
15317169044Sbrutus  */
15417169044Sbrutus int
15517169044Sbrutus _info(struct modinfo *modinfop)
15617169044Sbrutus {
15717169044Sbrutus 	return (mod_info(&ioat_modlinkage, modinfop));
15817169044Sbrutus }
15917169044Sbrutus 
16017169044Sbrutus /*
16117169044Sbrutus  * _fini()
16217169044Sbrutus  */
16317169044Sbrutus int
16417169044Sbrutus _fini(void)
16517169044Sbrutus {
16617169044Sbrutus 	int e;
16717169044Sbrutus 
16817169044Sbrutus 	e = mod_remove(&ioat_modlinkage);
16917169044Sbrutus 	if (e != 0) {
17017169044Sbrutus 		return (e);
17117169044Sbrutus 	}
17217169044Sbrutus 
17317169044Sbrutus 	ddi_soft_state_fini(&ioat_statep);
17417169044Sbrutus 
17517169044Sbrutus 	return (0);
17617169044Sbrutus }
17717169044Sbrutus 
17817169044Sbrutus /*
17917169044Sbrutus  * ioat_attach()
18017169044Sbrutus  */
18117169044Sbrutus static int
18217169044Sbrutus ioat_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
18317169044Sbrutus {
18417169044Sbrutus 	ioat_state_t *state;
18517169044Sbrutus 	int instance;
18617169044Sbrutus 	int e;
18717169044Sbrutus 
18817169044Sbrutus 
18917169044Sbrutus 	switch (cmd) {
19017169044Sbrutus 	case DDI_ATTACH:
19117169044Sbrutus 		break;
19217169044Sbrutus 
19317169044Sbrutus 	case DDI_RESUME:
19417169044Sbrutus 		instance = ddi_get_instance(dip);
19517169044Sbrutus 		state = ddi_get_soft_state(ioat_statep, instance);
19617169044Sbrutus 		if (state == NULL) {
19717169044Sbrutus 			return (DDI_FAILURE);
19817169044Sbrutus 		}
19917169044Sbrutus 		e = ioat_channel_resume(state);
20017169044Sbrutus 		if (e != DDI_SUCCESS) {
20117169044Sbrutus 			return (DDI_FAILURE);
20217169044Sbrutus 		}
20317169044Sbrutus 		ioat_intr_enable(state);
20417169044Sbrutus 		return (DDI_SUCCESS);
20517169044Sbrutus 
20617169044Sbrutus 	default:
20717169044Sbrutus 		return (DDI_FAILURE);
20817169044Sbrutus 	}
20917169044Sbrutus 
21017169044Sbrutus 	instance = ddi_get_instance(dip);
21117169044Sbrutus 	e = ddi_soft_state_zalloc(ioat_statep, instance);
21217169044Sbrutus 	if (e != DDI_SUCCESS) {
21317169044Sbrutus 		return (DDI_FAILURE);
21417169044Sbrutus 	}
21517169044Sbrutus 	state = ddi_get_soft_state(ioat_statep, instance);
21617169044Sbrutus 	if (state == NULL) {
21717169044Sbrutus 		goto attachfail_get_soft_state;
21817169044Sbrutus 	}
21917169044Sbrutus 
22017169044Sbrutus 	state->is_dip = dip;
22117169044Sbrutus 	state->is_instance = instance;
22217169044Sbrutus 
22317169044Sbrutus 	/* setup the registers, save away some device info */
22417169044Sbrutus 	e = ioat_chip_init(state);
22517169044Sbrutus 	if (e != DDI_SUCCESS) {
22617169044Sbrutus 		goto attachfail_chip_init;
22717169044Sbrutus 	}
22817169044Sbrutus 
22917169044Sbrutus 	/* initialize driver state, must be after chip init */
23017169044Sbrutus 	e = ioat_drv_init(state);
23117169044Sbrutus 	if (e != DDI_SUCCESS) {
23217169044Sbrutus 		goto attachfail_drv_init;
23317169044Sbrutus 	}
23417169044Sbrutus 
23517169044Sbrutus 	/* create the minor node (for the ioctl) */
23617169044Sbrutus 	e = ddi_create_minor_node(dip, "ioat", S_IFCHR, instance, DDI_PSEUDO,
23717169044Sbrutus 	    0);
23817169044Sbrutus 	if (e != DDI_SUCCESS) {
23917169044Sbrutus 		goto attachfail_minor_node;
24017169044Sbrutus 	}
24117169044Sbrutus 
24217169044Sbrutus 	/* Enable device interrupts */
24317169044Sbrutus 	ioat_intr_enable(state);
24417169044Sbrutus 
24517169044Sbrutus 	/* Report that driver was loaded */
24617169044Sbrutus 	ddi_report_dev(dip);
24717169044Sbrutus 
24817169044Sbrutus 	/* register with dcopy */
24917169044Sbrutus 	e = dcopy_device_register(state, &state->is_deviceinfo,
25017169044Sbrutus 	    &state->is_device_handle);
25117169044Sbrutus 	if (e != DCOPY_SUCCESS) {
25217169044Sbrutus 		goto attachfail_register;
25317169044Sbrutus 	}
25417169044Sbrutus 
25517169044Sbrutus 	return (DDI_SUCCESS);
25617169044Sbrutus 
25717169044Sbrutus attachfail_register:
25817169044Sbrutus 	ioat_intr_disable(state);
25917169044Sbrutus 	ddi_remove_minor_node(dip, NULL);
26017169044Sbrutus attachfail_minor_node:
26117169044Sbrutus 	ioat_drv_fini(state);
26217169044Sbrutus attachfail_drv_init:
26317169044Sbrutus 	ioat_chip_fini(state);
26417169044Sbrutus attachfail_chip_init:
26517169044Sbrutus attachfail_get_soft_state:
26617169044Sbrutus 	(void) ddi_soft_state_free(ioat_statep, instance);
26717169044Sbrutus 
26817169044Sbrutus 	return (DDI_FAILURE);
26917169044Sbrutus }
27017169044Sbrutus 
27117169044Sbrutus /*
27217169044Sbrutus  * ioat_detach()
27317169044Sbrutus  */
27417169044Sbrutus static int
27517169044Sbrutus ioat_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
27617169044Sbrutus {
27717169044Sbrutus 	ioat_state_t *state;
27817169044Sbrutus 	int instance;
27917169044Sbrutus 	int e;
28017169044Sbrutus 
28117169044Sbrutus 
28217169044Sbrutus 	instance = ddi_get_instance(dip);
28317169044Sbrutus 	state = ddi_get_soft_state(ioat_statep, instance);
28417169044Sbrutus 	if (state == NULL) {
28517169044Sbrutus 		return (DDI_FAILURE);
28617169044Sbrutus 	}
28717169044Sbrutus 
28817169044Sbrutus 	switch (cmd) {
28917169044Sbrutus 	case DDI_DETACH:
29017169044Sbrutus 		break;
29117169044Sbrutus 
29217169044Sbrutus 	case DDI_SUSPEND:
29317169044Sbrutus 		ioat_channel_suspend(state);
29417169044Sbrutus 		return (DDI_SUCCESS);
29517169044Sbrutus 
29617169044Sbrutus 	default:
29717169044Sbrutus 		return (DDI_FAILURE);
29817169044Sbrutus 	}
29917169044Sbrutus 
30017169044Sbrutus 	/*
30117169044Sbrutus 	 * try to unregister from dcopy.  Since this driver doesn't follow the
30217169044Sbrutus 	 * traditional parent/child model, we may still be in use so we can't
30317169044Sbrutus 	 * detach yet.
30417169044Sbrutus 	 */
30517169044Sbrutus 	e = dcopy_device_unregister(&state->is_device_handle);
30617169044Sbrutus 	if (e != DCOPY_SUCCESS) {
30717169044Sbrutus 		if (e == DCOPY_PENDING) {
30817169044Sbrutus 			cmn_err(CE_NOTE, "device busy, performing asynchronous"
30917169044Sbrutus 			    " detach\n");
31017169044Sbrutus 		}
31117169044Sbrutus 		return (DDI_FAILURE);
31217169044Sbrutus 	}
31317169044Sbrutus 
31417169044Sbrutus 	ioat_detach_finish(state);
31517169044Sbrutus 
31617169044Sbrutus 	return (DDI_SUCCESS);
31717169044Sbrutus }
31817169044Sbrutus 
31917169044Sbrutus /*
32017169044Sbrutus  * ioat_getinfo()
32117169044Sbrutus  */
32217169044Sbrutus /*ARGSUSED*/
32317169044Sbrutus static int
32417169044Sbrutus ioat_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **result)
32517169044Sbrutus {
32617169044Sbrutus 	ioat_state_t *state;
32717169044Sbrutus 	int instance;
32817169044Sbrutus 	dev_t dev;
32917169044Sbrutus 	int e;
33017169044Sbrutus 
33117169044Sbrutus 
33217169044Sbrutus 	dev = (dev_t)arg;
33317169044Sbrutus 	instance = getminor(dev);
33417169044Sbrutus 
33517169044Sbrutus 	switch (cmd) {
33617169044Sbrutus 	case DDI_INFO_DEVT2DEVINFO:
33717169044Sbrutus 		state = ddi_get_soft_state(ioat_statep, instance);
33817169044Sbrutus 		if (state == NULL) {
33917169044Sbrutus 			return (DDI_FAILURE);
34017169044Sbrutus 		}
34117169044Sbrutus 		*result = (void *)state->is_dip;
34217169044Sbrutus 		e = DDI_SUCCESS;
34317169044Sbrutus 		break;
34417169044Sbrutus 
34517169044Sbrutus 	case DDI_INFO_DEVT2INSTANCE:
34617169044Sbrutus 		*result = (void *)(uintptr_t)instance;
34717169044Sbrutus 		e = DDI_SUCCESS;
34817169044Sbrutus 		break;
34917169044Sbrutus 
35017169044Sbrutus 	default:
35117169044Sbrutus 		e = DDI_FAILURE;
35217169044Sbrutus 		break;
35317169044Sbrutus 	}
35417169044Sbrutus 
35517169044Sbrutus 	return (e);
35617169044Sbrutus }
35717169044Sbrutus 
35817169044Sbrutus 
35917169044Sbrutus /*
36017169044Sbrutus  * ioat_open()
36117169044Sbrutus  */
36217169044Sbrutus /*ARGSUSED*/
36317169044Sbrutus static int
36417169044Sbrutus ioat_open(dev_t *devp, int flag, int otyp, cred_t *cred)
36517169044Sbrutus {
36617169044Sbrutus 	ioat_state_t *state;
36717169044Sbrutus 	int instance;
36817169044Sbrutus 
36917169044Sbrutus 	instance = getminor(*devp);
37017169044Sbrutus 	state = ddi_get_soft_state(ioat_statep, instance);
37117169044Sbrutus 	if (state == NULL) {
37217169044Sbrutus 		return (ENXIO);
37317169044Sbrutus 	}
37417169044Sbrutus 
37517169044Sbrutus 	return (0);
37617169044Sbrutus }
37717169044Sbrutus 
37817169044Sbrutus 
37917169044Sbrutus /*
38017169044Sbrutus  * ioat_close()
38117169044Sbrutus  */
38217169044Sbrutus /*ARGSUSED*/
38317169044Sbrutus static int
38417169044Sbrutus ioat_close(dev_t devp, int flag, int otyp, cred_t *cred)
38517169044Sbrutus {
38617169044Sbrutus 	return (0);
38717169044Sbrutus }
38817169044Sbrutus 
38917169044Sbrutus 
39017169044Sbrutus /*
39117169044Sbrutus  * ioat_chip_init()
39217169044Sbrutus  */
39317169044Sbrutus static int
39417169044Sbrutus ioat_chip_init(ioat_state_t *state)
39517169044Sbrutus {
39617169044Sbrutus 	ddi_device_acc_attr_t attr;
39717169044Sbrutus 	int e;
39817169044Sbrutus 
39917169044Sbrutus 
40017169044Sbrutus 	attr.devacc_attr_version = DDI_DEVICE_ATTR_V0;
40117169044Sbrutus 	attr.devacc_attr_endian_flags = DDI_NEVERSWAP_ACC;
40217169044Sbrutus 	attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC;
40317169044Sbrutus 
40417169044Sbrutus 	e =  ddi_regs_map_setup(state->is_dip, 1, (caddr_t *)&state->is_genregs,
40517169044Sbrutus 	    0, 0, &attr, &state->is_reg_handle);
40617169044Sbrutus 	if (e != DDI_SUCCESS) {
40717169044Sbrutus 		goto chipinitfail_regsmap;
40817169044Sbrutus 	}
40917169044Sbrutus 
41017169044Sbrutus 	/* save away ioat chip info */
41117169044Sbrutus 	state->is_num_channels = (uint_t)ddi_get8(state->is_reg_handle,
41217169044Sbrutus 	    &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 
42217169044Sbrutus 	state->is_maxxfer = (uint_t)ddi_get8(state->is_reg_handle,
42317169044Sbrutus 	    &state->is_genregs[IOAT_XFERCAP]);
42417169044Sbrutus 	state->is_chanoff = (uintptr_t)ddi_get16(state->is_reg_handle,
42517169044Sbrutus 	    (uint16_t *)&state->is_genregs[IOAT_PERPORT_OFF]);
42617169044Sbrutus 	state->is_cbver = (uint_t)ddi_get8(state->is_reg_handle,
42717169044Sbrutus 	    &state->is_genregs[IOAT_CBVER]);
42817169044Sbrutus 	state->is_intrdelay = (uint_t)ddi_get16(state->is_reg_handle,
42917169044Sbrutus 	    (uint16_t *)&state->is_genregs[IOAT_INTRDELAY]);
43017169044Sbrutus 	state->is_status = (uint_t)ddi_get16(state->is_reg_handle,
43117169044Sbrutus 	    (uint16_t *)&state->is_genregs[IOAT_CSSTATUS]);
43217169044Sbrutus 	state->is_capabilities = (uint_t)ddi_get32(state->is_reg_handle,
43317169044Sbrutus 	    (uint32_t *)&state->is_genregs[IOAT_DMACAPABILITY]);
43417169044Sbrutus 
43517169044Sbrutus 	if (state->is_cbver & 0x10) {
43617169044Sbrutus 		state->is_ver = IOAT_CBv1;
43717169044Sbrutus 	} else if (state->is_cbver & 0x20) {
43817169044Sbrutus 		state->is_ver = IOAT_CBv2;
43917169044Sbrutus 	} else {
44017169044Sbrutus 		goto chipinitfail_version;
44117169044Sbrutus 	}
44217169044Sbrutus 
44317169044Sbrutus 	return (DDI_SUCCESS);
44417169044Sbrutus 
44517169044Sbrutus chipinitfail_version:
446e6beb20cSmrj chipinitfail_numchan:
44717169044Sbrutus 	ddi_regs_map_free(&state->is_reg_handle);
44817169044Sbrutus chipinitfail_regsmap:
44917169044Sbrutus 	return (DDI_FAILURE);
45017169044Sbrutus }
45117169044Sbrutus 
45217169044Sbrutus 
45317169044Sbrutus /*
45417169044Sbrutus  * ioat_chip_fini()
45517169044Sbrutus  */
45617169044Sbrutus static void
45717169044Sbrutus ioat_chip_fini(ioat_state_t *state)
45817169044Sbrutus {
45917169044Sbrutus 	ddi_regs_map_free(&state->is_reg_handle);
46017169044Sbrutus }
46117169044Sbrutus 
46217169044Sbrutus 
46317169044Sbrutus /*
46417169044Sbrutus  * ioat_drv_init()
46517169044Sbrutus  */
46617169044Sbrutus static int
46717169044Sbrutus ioat_drv_init(ioat_state_t *state)
46817169044Sbrutus {
46917169044Sbrutus 	ddi_acc_handle_t handle;
47017169044Sbrutus 	int e;
47117169044Sbrutus 
47217169044Sbrutus 
47317169044Sbrutus 	mutex_init(&state->is_mutex, NULL, MUTEX_DRIVER, NULL);
47417169044Sbrutus 
47517169044Sbrutus 	state->is_deviceinfo.di_dip = state->is_dip;
47617169044Sbrutus 	state->is_deviceinfo.di_num_dma = state->is_num_channels;
47717169044Sbrutus 	state->is_deviceinfo.di_maxxfer = state->is_maxxfer;
47817169044Sbrutus 	state->is_deviceinfo.di_capabilities = state->is_capabilities;
47917169044Sbrutus 	state->is_deviceinfo.di_cb = &ioat_cb;
48017169044Sbrutus 
48117169044Sbrutus 	e = pci_config_setup(state->is_dip, &handle);
48217169044Sbrutus 	if (e != DDI_SUCCESS) {
48317169044Sbrutus 		goto drvinitfail_config_setup;
48417169044Sbrutus 	}
48517169044Sbrutus 
48617169044Sbrutus 	/* read in Vendor ID */
48717169044Sbrutus 	state->is_deviceinfo.di_id = (uint64_t)pci_config_get16(handle, 0);
48817169044Sbrutus 	state->is_deviceinfo.di_id = state->is_deviceinfo.di_id << 16;
48917169044Sbrutus 
49017169044Sbrutus 	/* read in Device ID */
49117169044Sbrutus 	state->is_deviceinfo.di_id |= (uint64_t)pci_config_get16(handle, 2);
49217169044Sbrutus 	state->is_deviceinfo.di_id = state->is_deviceinfo.di_id << 32;
49317169044Sbrutus 
49417169044Sbrutus 	/* Add in chipset version */
49517169044Sbrutus 	state->is_deviceinfo.di_id |= (uint64_t)state->is_cbver;
49617169044Sbrutus 	pci_config_teardown(&handle);
49717169044Sbrutus 
49817169044Sbrutus 	e = ddi_intr_hilevel(state->is_dip, 0);
49917169044Sbrutus 	if (e != 0) {
50017169044Sbrutus 		cmn_err(CE_WARN, "hilevel interrupt not supported\n");
50117169044Sbrutus 		goto drvinitfail_hilevel;
50217169044Sbrutus 	}
50317169044Sbrutus 
50417169044Sbrutus 	/* we don't support MSIs for v2 yet */
50517169044Sbrutus 	e = ddi_add_intr(state->is_dip, 0, NULL, NULL, ioat_isr,
50617169044Sbrutus 	    (caddr_t)state);
50717169044Sbrutus 	if (e != DDI_SUCCESS) {
50817169044Sbrutus 		goto drvinitfail_add_intr;
50917169044Sbrutus 	}
51017169044Sbrutus 
51117169044Sbrutus 	e = ddi_get_iblock_cookie(state->is_dip, 0, &state->is_iblock_cookie);
51217169044Sbrutus 	if (e != DDI_SUCCESS) {
51317169044Sbrutus 		goto drvinitfail_iblock_cookie;
51417169044Sbrutus 	}
51517169044Sbrutus 
51617169044Sbrutus 	e = ioat_channel_init(state);
51717169044Sbrutus 	if (e != DDI_SUCCESS) {
51817169044Sbrutus 		goto drvinitfail_channel_init;
51917169044Sbrutus 	}
52017169044Sbrutus 
52117169044Sbrutus 	return (DDI_SUCCESS);
52217169044Sbrutus 
52317169044Sbrutus drvinitfail_channel_init:
52417169044Sbrutus drvinitfail_iblock_cookie:
52517169044Sbrutus 	ddi_remove_intr(state->is_dip, 0, state->is_iblock_cookie);
52617169044Sbrutus drvinitfail_add_intr:
52717169044Sbrutus drvinitfail_hilevel:
52817169044Sbrutus drvinitfail_config_setup:
52917169044Sbrutus 	mutex_destroy(&state->is_mutex);
53017169044Sbrutus 
53117169044Sbrutus 	return (DDI_FAILURE);
53217169044Sbrutus }
53317169044Sbrutus 
53417169044Sbrutus 
53517169044Sbrutus /*
53617169044Sbrutus  * ioat_drv_fini()
53717169044Sbrutus  */
53817169044Sbrutus static void
53917169044Sbrutus ioat_drv_fini(ioat_state_t *state)
54017169044Sbrutus {
54117169044Sbrutus 	ioat_channel_fini(state);
54217169044Sbrutus 	ddi_remove_intr(state->is_dip, 0, state->is_iblock_cookie);
54317169044Sbrutus 	mutex_destroy(&state->is_mutex);
54417169044Sbrutus }
54517169044Sbrutus 
54617169044Sbrutus 
54717169044Sbrutus /*
54817169044Sbrutus  * ioat_unregister_complete()
54917169044Sbrutus  */
55017169044Sbrutus void
55117169044Sbrutus ioat_unregister_complete(void *device_private, int status)
55217169044Sbrutus {
55317169044Sbrutus 	ioat_state_t *state;
55417169044Sbrutus 
55517169044Sbrutus 
55617169044Sbrutus 	state = device_private;
55717169044Sbrutus 
55817169044Sbrutus 	if (status != DCOPY_SUCCESS) {
55917169044Sbrutus 		cmn_err(CE_WARN, "asynchronous detach aborted\n");
56017169044Sbrutus 		return;
56117169044Sbrutus 	}
56217169044Sbrutus 
56317169044Sbrutus 	cmn_err(CE_CONT, "detach completing\n");
56417169044Sbrutus 	ioat_detach_finish(state);
56517169044Sbrutus }
56617169044Sbrutus 
56717169044Sbrutus 
56817169044Sbrutus /*
56917169044Sbrutus  * ioat_detach_finish()
57017169044Sbrutus  */
57117169044Sbrutus void
57217169044Sbrutus ioat_detach_finish(ioat_state_t *state)
57317169044Sbrutus {
57417169044Sbrutus 	ioat_intr_disable(state);
57517169044Sbrutus 	ddi_remove_minor_node(state->is_dip, NULL);
57617169044Sbrutus 	ioat_drv_fini(state);
57717169044Sbrutus 	ioat_chip_fini(state);
57817169044Sbrutus 	(void) ddi_soft_state_free(ioat_statep, state->is_instance);
57917169044Sbrutus }
58017169044Sbrutus 
58117169044Sbrutus 
58217169044Sbrutus /*
58317169044Sbrutus  * ioat_intr_enable()
58417169044Sbrutus  */
58517169044Sbrutus static void
58617169044Sbrutus ioat_intr_enable(ioat_state_t *state)
58717169044Sbrutus {
58817169044Sbrutus 	uint32_t intr_status;
58917169044Sbrutus 
59017169044Sbrutus 
59117169044Sbrutus 	/* Clear any pending interrupts */
59217169044Sbrutus 	intr_status = ddi_get32(state->is_reg_handle,
59317169044Sbrutus 	    (uint32_t *)&state->is_genregs[IOAT_ATTNSTATUS]);
59417169044Sbrutus 	if (intr_status != 0) {
59517169044Sbrutus 		ddi_put32(state->is_reg_handle,
59617169044Sbrutus 		    (uint32_t *)&state->is_genregs[IOAT_ATTNSTATUS],
59717169044Sbrutus 		    intr_status);
59817169044Sbrutus 	}
59917169044Sbrutus 
60017169044Sbrutus 	/* Enable interrupts on the device */
60117169044Sbrutus 	ddi_put8(state->is_reg_handle, &state->is_genregs[IOAT_INTRCTL],
60217169044Sbrutus 	    IOAT_INTRCTL_MASTER_EN);
60317169044Sbrutus }
60417169044Sbrutus 
60517169044Sbrutus 
60617169044Sbrutus /*
60717169044Sbrutus  * ioat_intr_disable()
60817169044Sbrutus  */
60917169044Sbrutus static void
61017169044Sbrutus ioat_intr_disable(ioat_state_t *state)
61117169044Sbrutus {
61217169044Sbrutus 	/*
61317169044Sbrutus 	 * disable interrupts on the device. A read of the interrupt control
61417169044Sbrutus 	 * register clears the enable bit.
61517169044Sbrutus 	 */
61617169044Sbrutus 	(void) ddi_get8(state->is_reg_handle,
61717169044Sbrutus 	    &state->is_genregs[IOAT_INTRCTL]);
61817169044Sbrutus }
61917169044Sbrutus 
62017169044Sbrutus 
62117169044Sbrutus /*
62217169044Sbrutus  * ioat_isr()
62317169044Sbrutus  */
62417169044Sbrutus static uint_t
62517169044Sbrutus ioat_isr(caddr_t parm)
62617169044Sbrutus {
62717169044Sbrutus 	uint32_t intr_status;
62817169044Sbrutus 	ioat_state_t *state;
62917169044Sbrutus 	uint8_t intrctrl;
63017169044Sbrutus 	uint32_t chan;
63117169044Sbrutus 	uint_t r;
63217169044Sbrutus 	int i;
63317169044Sbrutus 
63417169044Sbrutus 	state = (ioat_state_t *)parm;
63517169044Sbrutus 
63617169044Sbrutus 	intrctrl = ddi_get8(state->is_reg_handle,
63717169044Sbrutus 	    &state->is_genregs[IOAT_INTRCTL]);
63817169044Sbrutus 	/* master interrupt enable should always be set */
63917169044Sbrutus 	ASSERT(intrctrl & IOAT_INTRCTL_MASTER_EN);
64017169044Sbrutus 
64117169044Sbrutus 	/* If the interrupt status bit isn't set, it's not ours */
64217169044Sbrutus 	if (!(intrctrl & IOAT_INTRCTL_INTR_STAT)) {
64317169044Sbrutus 		/* re-set master interrupt enable (since it clears on read) */
64417169044Sbrutus 		ddi_put8(state->is_reg_handle,
64517169044Sbrutus 		    &state->is_genregs[IOAT_INTRCTL], intrctrl);
64617169044Sbrutus 		return (DDI_INTR_UNCLAIMED);
64717169044Sbrutus 	}
64817169044Sbrutus 
64917169044Sbrutus 	/* see which channels generated the interrupt */
65017169044Sbrutus 	intr_status = ddi_get32(state->is_reg_handle,
65117169044Sbrutus 	    (uint32_t *)&state->is_genregs[IOAT_ATTNSTATUS]);
65217169044Sbrutus 
65317169044Sbrutus 	/* call the intr handler for the channels */
65417169044Sbrutus 	r = DDI_INTR_UNCLAIMED;
65517169044Sbrutus 	chan = 1;
65617169044Sbrutus 	for (i = 0; i < state->is_num_channels; i++) {
65717169044Sbrutus 		if (intr_status & chan) {
65817169044Sbrutus 			ioat_channel_intr(&state->is_channel[i]);
65917169044Sbrutus 			r = DDI_INTR_CLAIMED;
66017169044Sbrutus 		}
66117169044Sbrutus 		chan = chan << 1;
66217169044Sbrutus 	}
66317169044Sbrutus 
66417169044Sbrutus 	/*
66517169044Sbrutus 	 * if interrupt status bit was set, there should have been an
66617169044Sbrutus 	 * attention status bit set too.
66717169044Sbrutus 	 */
66817169044Sbrutus 	ASSERT(r == DDI_INTR_CLAIMED);
66917169044Sbrutus 
67017169044Sbrutus 	/* re-set master interrupt enable (since it clears on read) */
67117169044Sbrutus 	ddi_put8(state->is_reg_handle, &state->is_genregs[IOAT_INTRCTL],
67217169044Sbrutus 	    intrctrl);
67317169044Sbrutus 
67417169044Sbrutus 	return (r);
67517169044Sbrutus }
676*19397407SSherry Moore 
677*19397407SSherry Moore static int
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