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