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
_init(void)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
_info(struct modinfo * modinfop)15517169044Sbrutus _info(struct modinfo *modinfop)
15617169044Sbrutus {
15717169044Sbrutus return (mod_info(&ioat_modlinkage, modinfop));
15817169044Sbrutus }
15917169044Sbrutus
16017169044Sbrutus /*
16117169044Sbrutus * _fini()
16217169044Sbrutus */
16317169044Sbrutus int
_fini(void)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
ioat_attach(dev_info_t * dip,ddi_attach_cmd_t cmd)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
ioat_detach(dev_info_t * dip,ddi_detach_cmd_t cmd)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
ioat_getinfo(dev_info_t * dip,ddi_info_cmd_t cmd,void * arg,void ** result)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
ioat_open(dev_t * devp,int flag,int otyp,cred_t * cred)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
ioat_close(dev_t devp,int flag,int otyp,cred_t * cred)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
ioat_chip_init(ioat_state_t * state)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
ioat_chip_fini(ioat_state_t * state)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
ioat_drv_init(ioat_state_t * state)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
ioat_drv_fini(ioat_state_t * state)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
ioat_unregister_complete(void * device_private,int status)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
ioat_detach_finish(ioat_state_t * state)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
ioat_intr_enable(ioat_state_t * state)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
ioat_intr_disable(ioat_state_t * state)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
ioat_isr(caddr_t parm)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
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