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