1*6707Sbrutus /* 2*6707Sbrutus * CDDL HEADER START 3*6707Sbrutus * 4*6707Sbrutus * The contents of this file are subject to the terms of the 5*6707Sbrutus * Common Development and Distribution License (the "License"). 6*6707Sbrutus * You may not use this file except in compliance with the License. 7*6707Sbrutus * 8*6707Sbrutus * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9*6707Sbrutus * or http://www.opensolaris.org/os/licensing. 10*6707Sbrutus * See the License for the specific language governing permissions 11*6707Sbrutus * and limitations under the License. 12*6707Sbrutus * 13*6707Sbrutus * When distributing Covered Code, include this CDDL HEADER in each 14*6707Sbrutus * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15*6707Sbrutus * If applicable, add the following below this CDDL HEADER, with the 16*6707Sbrutus * fields enclosed by brackets "[]" replaced with your own identifying 17*6707Sbrutus * information: Portions Copyright [yyyy] [name of copyright owner] 18*6707Sbrutus * 19*6707Sbrutus * CDDL HEADER END 20*6707Sbrutus */ 21*6707Sbrutus 22*6707Sbrutus /* 23*6707Sbrutus * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 24*6707Sbrutus * Use is subject to license terms. 25*6707Sbrutus */ 26*6707Sbrutus 27*6707Sbrutus #pragma ident "%Z%%M% %I% %E% SMI" 28*6707Sbrutus 29*6707Sbrutus #include <sys/errno.h> 30*6707Sbrutus #include <sys/types.h> 31*6707Sbrutus #include <sys/conf.h> 32*6707Sbrutus #include <sys/kmem.h> 33*6707Sbrutus #include <sys/ddi.h> 34*6707Sbrutus #include <sys/stat.h> 35*6707Sbrutus #include <sys/sunddi.h> 36*6707Sbrutus #include <sys/file.h> 37*6707Sbrutus #include <sys/open.h> 38*6707Sbrutus #include <sys/modctl.h> 39*6707Sbrutus #include <sys/ddi_impldefs.h> 40*6707Sbrutus #include <sys/sysmacros.h> 41*6707Sbrutus 42*6707Sbrutus #include <sys/ioat.h> 43*6707Sbrutus 44*6707Sbrutus static int ioat_open(dev_t *devp, int flag, int otyp, cred_t *cred); 45*6707Sbrutus static int ioat_close(dev_t devp, int flag, int otyp, cred_t *cred); 46*6707Sbrutus static int ioat_attach(dev_info_t *devi, ddi_attach_cmd_t cmd); 47*6707Sbrutus static int ioat_detach(dev_info_t *devi, ddi_detach_cmd_t cmd); 48*6707Sbrutus static int ioat_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, 49*6707Sbrutus void **result); 50*6707Sbrutus 51*6707Sbrutus static struct cb_ops ioat_cb_ops = { 52*6707Sbrutus ioat_open, /* cb_open */ 53*6707Sbrutus ioat_close, /* cb_close */ 54*6707Sbrutus nodev, /* cb_strategy */ 55*6707Sbrutus nodev, /* cb_print */ 56*6707Sbrutus nodev, /* cb_dump */ 57*6707Sbrutus nodev, /* cb_read */ 58*6707Sbrutus nodev, /* cb_write */ 59*6707Sbrutus ioat_ioctl, /* cb_ioctl */ 60*6707Sbrutus nodev, /* cb_devmap */ 61*6707Sbrutus nodev, /* cb_mmap */ 62*6707Sbrutus nodev, /* cb_segmap */ 63*6707Sbrutus nochpoll, /* cb_chpoll */ 64*6707Sbrutus ddi_prop_op, /* cb_prop_op */ 65*6707Sbrutus NULL, /* cb_stream */ 66*6707Sbrutus D_NEW | D_MP | D_64BIT | D_DEVMAP, /* cb_flag */ 67*6707Sbrutus CB_REV 68*6707Sbrutus }; 69*6707Sbrutus 70*6707Sbrutus static struct dev_ops ioat_dev_ops = { 71*6707Sbrutus DEVO_REV, /* devo_rev */ 72*6707Sbrutus 0, /* devo_refcnt */ 73*6707Sbrutus ioat_getinfo, /* devo_getinfo */ 74*6707Sbrutus nulldev, /* devo_identify */ 75*6707Sbrutus nulldev, /* devo_probe */ 76*6707Sbrutus ioat_attach, /* devo_attach */ 77*6707Sbrutus ioat_detach, /* devo_detach */ 78*6707Sbrutus nodev, /* devo_reset */ 79*6707Sbrutus &ioat_cb_ops, /* devo_cb_ops */ 80*6707Sbrutus NULL, /* devo_bus_ops */ 81*6707Sbrutus NULL /* power */ 82*6707Sbrutus }; 83*6707Sbrutus 84*6707Sbrutus static struct modldrv ioat_modldrv = { 85*6707Sbrutus &mod_driverops, /* Type of module. This one is a driver */ 86*6707Sbrutus "ioat driver v%I%", /* Name of the module. */ 87*6707Sbrutus &ioat_dev_ops, /* driver ops */ 88*6707Sbrutus }; 89*6707Sbrutus 90*6707Sbrutus static struct modlinkage ioat_modlinkage = { 91*6707Sbrutus MODREV_1, 92*6707Sbrutus (void *) &ioat_modldrv, 93*6707Sbrutus NULL 94*6707Sbrutus }; 95*6707Sbrutus 96*6707Sbrutus 97*6707Sbrutus void *ioat_statep; 98*6707Sbrutus 99*6707Sbrutus static int ioat_chip_init(ioat_state_t *state); 100*6707Sbrutus static void ioat_chip_fini(ioat_state_t *state); 101*6707Sbrutus static int ioat_drv_init(ioat_state_t *state); 102*6707Sbrutus static void ioat_drv_fini(ioat_state_t *state); 103*6707Sbrutus static uint_t ioat_isr(caddr_t parm); 104*6707Sbrutus static void ioat_intr_enable(ioat_state_t *state); 105*6707Sbrutus static void ioat_intr_disable(ioat_state_t *state); 106*6707Sbrutus void ioat_detach_finish(ioat_state_t *state); 107*6707Sbrutus 108*6707Sbrutus 109*6707Sbrutus ddi_device_acc_attr_t ioat_acc_attr = { 110*6707Sbrutus DDI_DEVICE_ATTR_V0, /* devacc_attr_version */ 111*6707Sbrutus DDI_NEVERSWAP_ACC, /* devacc_attr_endian_flags */ 112*6707Sbrutus DDI_STORECACHING_OK_ACC, /* devacc_attr_dataorder */ 113*6707Sbrutus DDI_DEFAULT_ACC /* devacc_attr_access */ 114*6707Sbrutus }; 115*6707Sbrutus 116*6707Sbrutus /* dcopy callback interface */ 117*6707Sbrutus dcopy_device_cb_t ioat_cb = { 118*6707Sbrutus DCOPY_DEVICECB_V0, 119*6707Sbrutus 0, /* reserved */ 120*6707Sbrutus ioat_channel_alloc, 121*6707Sbrutus ioat_channel_free, 122*6707Sbrutus ioat_cmd_alloc, 123*6707Sbrutus ioat_cmd_free, 124*6707Sbrutus ioat_cmd_post, 125*6707Sbrutus ioat_cmd_poll, 126*6707Sbrutus ioat_unregister_complete 127*6707Sbrutus }; 128*6707Sbrutus 129*6707Sbrutus /* 130*6707Sbrutus * _init() 131*6707Sbrutus */ 132*6707Sbrutus int 133*6707Sbrutus _init(void) 134*6707Sbrutus { 135*6707Sbrutus int e; 136*6707Sbrutus 137*6707Sbrutus e = ddi_soft_state_init(&ioat_statep, sizeof (ioat_state_t), 1); 138*6707Sbrutus if (e != 0) { 139*6707Sbrutus return (e); 140*6707Sbrutus } 141*6707Sbrutus 142*6707Sbrutus e = mod_install(&ioat_modlinkage); 143*6707Sbrutus if (e != 0) { 144*6707Sbrutus ddi_soft_state_fini(&ioat_statep); 145*6707Sbrutus return (e); 146*6707Sbrutus } 147*6707Sbrutus 148*6707Sbrutus return (0); 149*6707Sbrutus } 150*6707Sbrutus 151*6707Sbrutus /* 152*6707Sbrutus * _info() 153*6707Sbrutus */ 154*6707Sbrutus int 155*6707Sbrutus _info(struct modinfo *modinfop) 156*6707Sbrutus { 157*6707Sbrutus return (mod_info(&ioat_modlinkage, modinfop)); 158*6707Sbrutus } 159*6707Sbrutus 160*6707Sbrutus /* 161*6707Sbrutus * _fini() 162*6707Sbrutus */ 163*6707Sbrutus int 164*6707Sbrutus _fini(void) 165*6707Sbrutus { 166*6707Sbrutus int e; 167*6707Sbrutus 168*6707Sbrutus e = mod_remove(&ioat_modlinkage); 169*6707Sbrutus if (e != 0) { 170*6707Sbrutus return (e); 171*6707Sbrutus } 172*6707Sbrutus 173*6707Sbrutus ddi_soft_state_fini(&ioat_statep); 174*6707Sbrutus 175*6707Sbrutus return (0); 176*6707Sbrutus } 177*6707Sbrutus 178*6707Sbrutus /* 179*6707Sbrutus * ioat_attach() 180*6707Sbrutus */ 181*6707Sbrutus static int 182*6707Sbrutus ioat_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 183*6707Sbrutus { 184*6707Sbrutus ioat_state_t *state; 185*6707Sbrutus int instance; 186*6707Sbrutus int e; 187*6707Sbrutus 188*6707Sbrutus 189*6707Sbrutus switch (cmd) { 190*6707Sbrutus case DDI_ATTACH: 191*6707Sbrutus break; 192*6707Sbrutus 193*6707Sbrutus case DDI_RESUME: 194*6707Sbrutus instance = ddi_get_instance(dip); 195*6707Sbrutus state = ddi_get_soft_state(ioat_statep, instance); 196*6707Sbrutus if (state == NULL) { 197*6707Sbrutus return (DDI_FAILURE); 198*6707Sbrutus } 199*6707Sbrutus e = ioat_channel_resume(state); 200*6707Sbrutus if (e != DDI_SUCCESS) { 201*6707Sbrutus return (DDI_FAILURE); 202*6707Sbrutus } 203*6707Sbrutus ioat_intr_enable(state); 204*6707Sbrutus return (DDI_SUCCESS); 205*6707Sbrutus 206*6707Sbrutus default: 207*6707Sbrutus return (DDI_FAILURE); 208*6707Sbrutus } 209*6707Sbrutus 210*6707Sbrutus instance = ddi_get_instance(dip); 211*6707Sbrutus e = ddi_soft_state_zalloc(ioat_statep, instance); 212*6707Sbrutus if (e != DDI_SUCCESS) { 213*6707Sbrutus return (DDI_FAILURE); 214*6707Sbrutus } 215*6707Sbrutus state = ddi_get_soft_state(ioat_statep, instance); 216*6707Sbrutus if (state == NULL) { 217*6707Sbrutus goto attachfail_get_soft_state; 218*6707Sbrutus } 219*6707Sbrutus 220*6707Sbrutus state->is_dip = dip; 221*6707Sbrutus state->is_instance = instance; 222*6707Sbrutus 223*6707Sbrutus /* setup the registers, save away some device info */ 224*6707Sbrutus e = ioat_chip_init(state); 225*6707Sbrutus if (e != DDI_SUCCESS) { 226*6707Sbrutus goto attachfail_chip_init; 227*6707Sbrutus } 228*6707Sbrutus 229*6707Sbrutus /* initialize driver state, must be after chip init */ 230*6707Sbrutus e = ioat_drv_init(state); 231*6707Sbrutus if (e != DDI_SUCCESS) { 232*6707Sbrutus goto attachfail_drv_init; 233*6707Sbrutus } 234*6707Sbrutus 235*6707Sbrutus /* create the minor node (for the ioctl) */ 236*6707Sbrutus e = ddi_create_minor_node(dip, "ioat", S_IFCHR, instance, DDI_PSEUDO, 237*6707Sbrutus 0); 238*6707Sbrutus if (e != DDI_SUCCESS) { 239*6707Sbrutus goto attachfail_minor_node; 240*6707Sbrutus } 241*6707Sbrutus 242*6707Sbrutus /* Enable device interrupts */ 243*6707Sbrutus ioat_intr_enable(state); 244*6707Sbrutus 245*6707Sbrutus /* Report that driver was loaded */ 246*6707Sbrutus ddi_report_dev(dip); 247*6707Sbrutus 248*6707Sbrutus /* register with dcopy */ 249*6707Sbrutus e = dcopy_device_register(state, &state->is_deviceinfo, 250*6707Sbrutus &state->is_device_handle); 251*6707Sbrutus if (e != DCOPY_SUCCESS) { 252*6707Sbrutus goto attachfail_register; 253*6707Sbrutus } 254*6707Sbrutus 255*6707Sbrutus return (DDI_SUCCESS); 256*6707Sbrutus 257*6707Sbrutus attachfail_register: 258*6707Sbrutus ioat_intr_disable(state); 259*6707Sbrutus ddi_remove_minor_node(dip, NULL); 260*6707Sbrutus attachfail_minor_node: 261*6707Sbrutus ioat_drv_fini(state); 262*6707Sbrutus attachfail_drv_init: 263*6707Sbrutus ioat_chip_fini(state); 264*6707Sbrutus attachfail_chip_init: 265*6707Sbrutus attachfail_get_soft_state: 266*6707Sbrutus (void) ddi_soft_state_free(ioat_statep, instance); 267*6707Sbrutus 268*6707Sbrutus return (DDI_FAILURE); 269*6707Sbrutus } 270*6707Sbrutus 271*6707Sbrutus /* 272*6707Sbrutus * ioat_detach() 273*6707Sbrutus */ 274*6707Sbrutus static int 275*6707Sbrutus ioat_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 276*6707Sbrutus { 277*6707Sbrutus ioat_state_t *state; 278*6707Sbrutus int instance; 279*6707Sbrutus int e; 280*6707Sbrutus 281*6707Sbrutus 282*6707Sbrutus instance = ddi_get_instance(dip); 283*6707Sbrutus state = ddi_get_soft_state(ioat_statep, instance); 284*6707Sbrutus if (state == NULL) { 285*6707Sbrutus return (DDI_FAILURE); 286*6707Sbrutus } 287*6707Sbrutus 288*6707Sbrutus switch (cmd) { 289*6707Sbrutus case DDI_DETACH: 290*6707Sbrutus break; 291*6707Sbrutus 292*6707Sbrutus case DDI_SUSPEND: 293*6707Sbrutus ioat_channel_suspend(state); 294*6707Sbrutus return (DDI_SUCCESS); 295*6707Sbrutus 296*6707Sbrutus default: 297*6707Sbrutus return (DDI_FAILURE); 298*6707Sbrutus } 299*6707Sbrutus 300*6707Sbrutus /* 301*6707Sbrutus * try to unregister from dcopy. Since this driver doesn't follow the 302*6707Sbrutus * traditional parent/child model, we may still be in use so we can't 303*6707Sbrutus * detach yet. 304*6707Sbrutus */ 305*6707Sbrutus e = dcopy_device_unregister(&state->is_device_handle); 306*6707Sbrutus if (e != DCOPY_SUCCESS) { 307*6707Sbrutus if (e == DCOPY_PENDING) { 308*6707Sbrutus cmn_err(CE_NOTE, "device busy, performing asynchronous" 309*6707Sbrutus " detach\n"); 310*6707Sbrutus } 311*6707Sbrutus return (DDI_FAILURE); 312*6707Sbrutus } 313*6707Sbrutus 314*6707Sbrutus ioat_detach_finish(state); 315*6707Sbrutus 316*6707Sbrutus return (DDI_SUCCESS); 317*6707Sbrutus } 318*6707Sbrutus 319*6707Sbrutus /* 320*6707Sbrutus * ioat_getinfo() 321*6707Sbrutus */ 322*6707Sbrutus /*ARGSUSED*/ 323*6707Sbrutus static int 324*6707Sbrutus ioat_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **result) 325*6707Sbrutus { 326*6707Sbrutus ioat_state_t *state; 327*6707Sbrutus int instance; 328*6707Sbrutus dev_t dev; 329*6707Sbrutus int e; 330*6707Sbrutus 331*6707Sbrutus 332*6707Sbrutus dev = (dev_t)arg; 333*6707Sbrutus instance = getminor(dev); 334*6707Sbrutus 335*6707Sbrutus switch (cmd) { 336*6707Sbrutus case DDI_INFO_DEVT2DEVINFO: 337*6707Sbrutus state = ddi_get_soft_state(ioat_statep, instance); 338*6707Sbrutus if (state == NULL) { 339*6707Sbrutus return (DDI_FAILURE); 340*6707Sbrutus } 341*6707Sbrutus *result = (void *)state->is_dip; 342*6707Sbrutus e = DDI_SUCCESS; 343*6707Sbrutus break; 344*6707Sbrutus 345*6707Sbrutus case DDI_INFO_DEVT2INSTANCE: 346*6707Sbrutus *result = (void *)(uintptr_t)instance; 347*6707Sbrutus e = DDI_SUCCESS; 348*6707Sbrutus break; 349*6707Sbrutus 350*6707Sbrutus default: 351*6707Sbrutus e = DDI_FAILURE; 352*6707Sbrutus break; 353*6707Sbrutus } 354*6707Sbrutus 355*6707Sbrutus return (e); 356*6707Sbrutus } 357*6707Sbrutus 358*6707Sbrutus 359*6707Sbrutus /* 360*6707Sbrutus * ioat_open() 361*6707Sbrutus */ 362*6707Sbrutus /*ARGSUSED*/ 363*6707Sbrutus static int 364*6707Sbrutus ioat_open(dev_t *devp, int flag, int otyp, cred_t *cred) 365*6707Sbrutus { 366*6707Sbrutus ioat_state_t *state; 367*6707Sbrutus int instance; 368*6707Sbrutus 369*6707Sbrutus instance = getminor(*devp); 370*6707Sbrutus state = ddi_get_soft_state(ioat_statep, instance); 371*6707Sbrutus if (state == NULL) { 372*6707Sbrutus return (ENXIO); 373*6707Sbrutus } 374*6707Sbrutus 375*6707Sbrutus return (0); 376*6707Sbrutus } 377*6707Sbrutus 378*6707Sbrutus 379*6707Sbrutus /* 380*6707Sbrutus * ioat_close() 381*6707Sbrutus */ 382*6707Sbrutus /*ARGSUSED*/ 383*6707Sbrutus static int 384*6707Sbrutus ioat_close(dev_t devp, int flag, int otyp, cred_t *cred) 385*6707Sbrutus { 386*6707Sbrutus return (0); 387*6707Sbrutus } 388*6707Sbrutus 389*6707Sbrutus 390*6707Sbrutus /* 391*6707Sbrutus * ioat_chip_init() 392*6707Sbrutus */ 393*6707Sbrutus static int 394*6707Sbrutus ioat_chip_init(ioat_state_t *state) 395*6707Sbrutus { 396*6707Sbrutus ddi_device_acc_attr_t attr; 397*6707Sbrutus int e; 398*6707Sbrutus 399*6707Sbrutus 400*6707Sbrutus attr.devacc_attr_version = DDI_DEVICE_ATTR_V0; 401*6707Sbrutus attr.devacc_attr_endian_flags = DDI_NEVERSWAP_ACC; 402*6707Sbrutus attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC; 403*6707Sbrutus 404*6707Sbrutus e = ddi_regs_map_setup(state->is_dip, 1, (caddr_t *)&state->is_genregs, 405*6707Sbrutus 0, 0, &attr, &state->is_reg_handle); 406*6707Sbrutus if (e != DDI_SUCCESS) { 407*6707Sbrutus goto chipinitfail_regsmap; 408*6707Sbrutus } 409*6707Sbrutus 410*6707Sbrutus /* save away ioat chip info */ 411*6707Sbrutus state->is_num_channels = (uint_t)ddi_get8(state->is_reg_handle, 412*6707Sbrutus &state->is_genregs[IOAT_CHANCNT]); 413*6707Sbrutus state->is_maxxfer = (uint_t)ddi_get8(state->is_reg_handle, 414*6707Sbrutus &state->is_genregs[IOAT_XFERCAP]); 415*6707Sbrutus state->is_chanoff = (uintptr_t)ddi_get16(state->is_reg_handle, 416*6707Sbrutus (uint16_t *)&state->is_genregs[IOAT_PERPORT_OFF]); 417*6707Sbrutus state->is_cbver = (uint_t)ddi_get8(state->is_reg_handle, 418*6707Sbrutus &state->is_genregs[IOAT_CBVER]); 419*6707Sbrutus state->is_intrdelay = (uint_t)ddi_get16(state->is_reg_handle, 420*6707Sbrutus (uint16_t *)&state->is_genregs[IOAT_INTRDELAY]); 421*6707Sbrutus state->is_status = (uint_t)ddi_get16(state->is_reg_handle, 422*6707Sbrutus (uint16_t *)&state->is_genregs[IOAT_CSSTATUS]); 423*6707Sbrutus state->is_capabilities = (uint_t)ddi_get32(state->is_reg_handle, 424*6707Sbrutus (uint32_t *)&state->is_genregs[IOAT_DMACAPABILITY]); 425*6707Sbrutus 426*6707Sbrutus if (state->is_cbver & 0x10) { 427*6707Sbrutus state->is_ver = IOAT_CBv1; 428*6707Sbrutus } else if (state->is_cbver & 0x20) { 429*6707Sbrutus state->is_ver = IOAT_CBv2; 430*6707Sbrutus } else { 431*6707Sbrutus goto chipinitfail_version; 432*6707Sbrutus } 433*6707Sbrutus 434*6707Sbrutus return (DDI_SUCCESS); 435*6707Sbrutus 436*6707Sbrutus chipinitfail_version: 437*6707Sbrutus ddi_regs_map_free(&state->is_reg_handle); 438*6707Sbrutus chipinitfail_regsmap: 439*6707Sbrutus return (DDI_FAILURE); 440*6707Sbrutus } 441*6707Sbrutus 442*6707Sbrutus 443*6707Sbrutus /* 444*6707Sbrutus * ioat_chip_fini() 445*6707Sbrutus */ 446*6707Sbrutus static void 447*6707Sbrutus ioat_chip_fini(ioat_state_t *state) 448*6707Sbrutus { 449*6707Sbrutus ddi_regs_map_free(&state->is_reg_handle); 450*6707Sbrutus } 451*6707Sbrutus 452*6707Sbrutus 453*6707Sbrutus /* 454*6707Sbrutus * ioat_drv_init() 455*6707Sbrutus */ 456*6707Sbrutus static int 457*6707Sbrutus ioat_drv_init(ioat_state_t *state) 458*6707Sbrutus { 459*6707Sbrutus ddi_acc_handle_t handle; 460*6707Sbrutus int e; 461*6707Sbrutus 462*6707Sbrutus 463*6707Sbrutus mutex_init(&state->is_mutex, NULL, MUTEX_DRIVER, NULL); 464*6707Sbrutus 465*6707Sbrutus state->is_deviceinfo.di_dip = state->is_dip; 466*6707Sbrutus state->is_deviceinfo.di_num_dma = state->is_num_channels; 467*6707Sbrutus state->is_deviceinfo.di_maxxfer = state->is_maxxfer; 468*6707Sbrutus state->is_deviceinfo.di_capabilities = state->is_capabilities; 469*6707Sbrutus state->is_deviceinfo.di_cb = &ioat_cb; 470*6707Sbrutus 471*6707Sbrutus e = pci_config_setup(state->is_dip, &handle); 472*6707Sbrutus if (e != DDI_SUCCESS) { 473*6707Sbrutus goto drvinitfail_config_setup; 474*6707Sbrutus } 475*6707Sbrutus 476*6707Sbrutus /* read in Vendor ID */ 477*6707Sbrutus state->is_deviceinfo.di_id = (uint64_t)pci_config_get16(handle, 0); 478*6707Sbrutus state->is_deviceinfo.di_id = state->is_deviceinfo.di_id << 16; 479*6707Sbrutus 480*6707Sbrutus /* read in Device ID */ 481*6707Sbrutus state->is_deviceinfo.di_id |= (uint64_t)pci_config_get16(handle, 2); 482*6707Sbrutus state->is_deviceinfo.di_id = state->is_deviceinfo.di_id << 32; 483*6707Sbrutus 484*6707Sbrutus /* Add in chipset version */ 485*6707Sbrutus state->is_deviceinfo.di_id |= (uint64_t)state->is_cbver; 486*6707Sbrutus pci_config_teardown(&handle); 487*6707Sbrutus 488*6707Sbrutus e = ddi_intr_hilevel(state->is_dip, 0); 489*6707Sbrutus if (e != 0) { 490*6707Sbrutus cmn_err(CE_WARN, "hilevel interrupt not supported\n"); 491*6707Sbrutus goto drvinitfail_hilevel; 492*6707Sbrutus } 493*6707Sbrutus 494*6707Sbrutus /* we don't support MSIs for v2 yet */ 495*6707Sbrutus e = ddi_add_intr(state->is_dip, 0, NULL, NULL, ioat_isr, 496*6707Sbrutus (caddr_t)state); 497*6707Sbrutus if (e != DDI_SUCCESS) { 498*6707Sbrutus goto drvinitfail_add_intr; 499*6707Sbrutus } 500*6707Sbrutus 501*6707Sbrutus e = ddi_get_iblock_cookie(state->is_dip, 0, &state->is_iblock_cookie); 502*6707Sbrutus if (e != DDI_SUCCESS) { 503*6707Sbrutus goto drvinitfail_iblock_cookie; 504*6707Sbrutus } 505*6707Sbrutus 506*6707Sbrutus e = ioat_channel_init(state); 507*6707Sbrutus if (e != DDI_SUCCESS) { 508*6707Sbrutus goto drvinitfail_channel_init; 509*6707Sbrutus } 510*6707Sbrutus 511*6707Sbrutus return (DDI_SUCCESS); 512*6707Sbrutus 513*6707Sbrutus drvinitfail_channel_init: 514*6707Sbrutus drvinitfail_iblock_cookie: 515*6707Sbrutus ddi_remove_intr(state->is_dip, 0, state->is_iblock_cookie); 516*6707Sbrutus drvinitfail_add_intr: 517*6707Sbrutus drvinitfail_hilevel: 518*6707Sbrutus drvinitfail_config_setup: 519*6707Sbrutus mutex_destroy(&state->is_mutex); 520*6707Sbrutus 521*6707Sbrutus return (DDI_FAILURE); 522*6707Sbrutus } 523*6707Sbrutus 524*6707Sbrutus 525*6707Sbrutus /* 526*6707Sbrutus * ioat_drv_fini() 527*6707Sbrutus */ 528*6707Sbrutus static void 529*6707Sbrutus ioat_drv_fini(ioat_state_t *state) 530*6707Sbrutus { 531*6707Sbrutus ioat_channel_fini(state); 532*6707Sbrutus ddi_remove_intr(state->is_dip, 0, state->is_iblock_cookie); 533*6707Sbrutus mutex_destroy(&state->is_mutex); 534*6707Sbrutus } 535*6707Sbrutus 536*6707Sbrutus 537*6707Sbrutus /* 538*6707Sbrutus * ioat_unregister_complete() 539*6707Sbrutus */ 540*6707Sbrutus void 541*6707Sbrutus ioat_unregister_complete(void *device_private, int status) 542*6707Sbrutus { 543*6707Sbrutus ioat_state_t *state; 544*6707Sbrutus 545*6707Sbrutus 546*6707Sbrutus state = device_private; 547*6707Sbrutus 548*6707Sbrutus if (status != DCOPY_SUCCESS) { 549*6707Sbrutus cmn_err(CE_WARN, "asynchronous detach aborted\n"); 550*6707Sbrutus return; 551*6707Sbrutus } 552*6707Sbrutus 553*6707Sbrutus cmn_err(CE_CONT, "detach completing\n"); 554*6707Sbrutus ioat_detach_finish(state); 555*6707Sbrutus } 556*6707Sbrutus 557*6707Sbrutus 558*6707Sbrutus /* 559*6707Sbrutus * ioat_detach_finish() 560*6707Sbrutus */ 561*6707Sbrutus void 562*6707Sbrutus ioat_detach_finish(ioat_state_t *state) 563*6707Sbrutus { 564*6707Sbrutus ioat_intr_disable(state); 565*6707Sbrutus ddi_remove_minor_node(state->is_dip, NULL); 566*6707Sbrutus ioat_drv_fini(state); 567*6707Sbrutus ioat_chip_fini(state); 568*6707Sbrutus (void) ddi_soft_state_free(ioat_statep, state->is_instance); 569*6707Sbrutus } 570*6707Sbrutus 571*6707Sbrutus 572*6707Sbrutus /* 573*6707Sbrutus * ioat_intr_enable() 574*6707Sbrutus */ 575*6707Sbrutus static void 576*6707Sbrutus ioat_intr_enable(ioat_state_t *state) 577*6707Sbrutus { 578*6707Sbrutus uint32_t intr_status; 579*6707Sbrutus 580*6707Sbrutus 581*6707Sbrutus /* Clear any pending interrupts */ 582*6707Sbrutus intr_status = ddi_get32(state->is_reg_handle, 583*6707Sbrutus (uint32_t *)&state->is_genregs[IOAT_ATTNSTATUS]); 584*6707Sbrutus if (intr_status != 0) { 585*6707Sbrutus ddi_put32(state->is_reg_handle, 586*6707Sbrutus (uint32_t *)&state->is_genregs[IOAT_ATTNSTATUS], 587*6707Sbrutus intr_status); 588*6707Sbrutus } 589*6707Sbrutus 590*6707Sbrutus /* Enable interrupts on the device */ 591*6707Sbrutus ddi_put8(state->is_reg_handle, &state->is_genregs[IOAT_INTRCTL], 592*6707Sbrutus IOAT_INTRCTL_MASTER_EN); 593*6707Sbrutus } 594*6707Sbrutus 595*6707Sbrutus 596*6707Sbrutus /* 597*6707Sbrutus * ioat_intr_disable() 598*6707Sbrutus */ 599*6707Sbrutus static void 600*6707Sbrutus ioat_intr_disable(ioat_state_t *state) 601*6707Sbrutus { 602*6707Sbrutus /* 603*6707Sbrutus * disable interrupts on the device. A read of the interrupt control 604*6707Sbrutus * register clears the enable bit. 605*6707Sbrutus */ 606*6707Sbrutus (void) ddi_get8(state->is_reg_handle, 607*6707Sbrutus &state->is_genregs[IOAT_INTRCTL]); 608*6707Sbrutus } 609*6707Sbrutus 610*6707Sbrutus 611*6707Sbrutus /* 612*6707Sbrutus * ioat_isr() 613*6707Sbrutus */ 614*6707Sbrutus static uint_t 615*6707Sbrutus ioat_isr(caddr_t parm) 616*6707Sbrutus { 617*6707Sbrutus uint32_t intr_status; 618*6707Sbrutus ioat_state_t *state; 619*6707Sbrutus uint8_t intrctrl; 620*6707Sbrutus uint32_t chan; 621*6707Sbrutus uint_t r; 622*6707Sbrutus int i; 623*6707Sbrutus 624*6707Sbrutus state = (ioat_state_t *)parm; 625*6707Sbrutus 626*6707Sbrutus intrctrl = ddi_get8(state->is_reg_handle, 627*6707Sbrutus &state->is_genregs[IOAT_INTRCTL]); 628*6707Sbrutus /* master interrupt enable should always be set */ 629*6707Sbrutus ASSERT(intrctrl & IOAT_INTRCTL_MASTER_EN); 630*6707Sbrutus 631*6707Sbrutus /* If the interrupt status bit isn't set, it's not ours */ 632*6707Sbrutus if (!(intrctrl & IOAT_INTRCTL_INTR_STAT)) { 633*6707Sbrutus /* re-set master interrupt enable (since it clears on read) */ 634*6707Sbrutus ddi_put8(state->is_reg_handle, 635*6707Sbrutus &state->is_genregs[IOAT_INTRCTL], intrctrl); 636*6707Sbrutus return (DDI_INTR_UNCLAIMED); 637*6707Sbrutus } 638*6707Sbrutus 639*6707Sbrutus /* see which channels generated the interrupt */ 640*6707Sbrutus intr_status = ddi_get32(state->is_reg_handle, 641*6707Sbrutus (uint32_t *)&state->is_genregs[IOAT_ATTNSTATUS]); 642*6707Sbrutus 643*6707Sbrutus /* call the intr handler for the channels */ 644*6707Sbrutus r = DDI_INTR_UNCLAIMED; 645*6707Sbrutus chan = 1; 646*6707Sbrutus for (i = 0; i < state->is_num_channels; i++) { 647*6707Sbrutus if (intr_status & chan) { 648*6707Sbrutus ioat_channel_intr(&state->is_channel[i]); 649*6707Sbrutus r = DDI_INTR_CLAIMED; 650*6707Sbrutus } 651*6707Sbrutus chan = chan << 1; 652*6707Sbrutus } 653*6707Sbrutus 654*6707Sbrutus /* 655*6707Sbrutus * if interrupt status bit was set, there should have been an 656*6707Sbrutus * attention status bit set too. 657*6707Sbrutus */ 658*6707Sbrutus ASSERT(r == DDI_INTR_CLAIMED); 659*6707Sbrutus 660*6707Sbrutus /* re-set master interrupt enable (since it clears on read) */ 661*6707Sbrutus ddi_put8(state->is_reg_handle, &state->is_genregs[IOAT_INTRCTL], 662*6707Sbrutus intrctrl); 663*6707Sbrutus 664*6707Sbrutus return (r); 665*6707Sbrutus } 666