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