18e50dcc9Sbrutus /*
28e50dcc9Sbrutus * CDDL HEADER START
38e50dcc9Sbrutus *
48e50dcc9Sbrutus * The contents of this file are subject to the terms of the
58e50dcc9Sbrutus * Common Development and Distribution License (the "License").
68e50dcc9Sbrutus * You may not use this file except in compliance with the License.
78e50dcc9Sbrutus *
88e50dcc9Sbrutus * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
98e50dcc9Sbrutus * or http://www.opensolaris.org/os/licensing.
108e50dcc9Sbrutus * See the License for the specific language governing permissions
118e50dcc9Sbrutus * and limitations under the License.
128e50dcc9Sbrutus *
138e50dcc9Sbrutus * When distributing Covered Code, include this CDDL HEADER in each
148e50dcc9Sbrutus * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
158e50dcc9Sbrutus * If applicable, add the following below this CDDL HEADER, with the
168e50dcc9Sbrutus * fields enclosed by brackets "[]" replaced with your own identifying
178e50dcc9Sbrutus * information: Portions Copyright [yyyy] [name of copyright owner]
188e50dcc9Sbrutus *
198e50dcc9Sbrutus * CDDL HEADER END
208e50dcc9Sbrutus */
218e50dcc9Sbrutus
228e50dcc9Sbrutus /*
238e50dcc9Sbrutus * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
248e50dcc9Sbrutus * Use is subject to license terms.
258e50dcc9Sbrutus */
268e50dcc9Sbrutus
278e50dcc9Sbrutus #include <sys/errno.h>
288e50dcc9Sbrutus #include <sys/types.h>
298e50dcc9Sbrutus #include <sys/conf.h>
308e50dcc9Sbrutus #include <sys/kmem.h>
318e50dcc9Sbrutus #include <sys/ddi.h>
328e50dcc9Sbrutus #include <sys/stat.h>
338e50dcc9Sbrutus #include <sys/sunddi.h>
348e50dcc9Sbrutus #include <sys/file.h>
358e50dcc9Sbrutus #include <sys/open.h>
368e50dcc9Sbrutus #include <sys/modctl.h>
378e50dcc9Sbrutus #include <sys/ddi_impldefs.h>
388e50dcc9Sbrutus #include <sys/sysmacros.h>
398e50dcc9Sbrutus
408e50dcc9Sbrutus #include <sys/ioat.h>
418e50dcc9Sbrutus
428e50dcc9Sbrutus static int ioat_open(dev_t *devp, int flag, int otyp, cred_t *cred);
438e50dcc9Sbrutus static int ioat_close(dev_t devp, int flag, int otyp, cred_t *cred);
448e50dcc9Sbrutus static int ioat_attach(dev_info_t *devi, ddi_attach_cmd_t cmd);
458e50dcc9Sbrutus static int ioat_detach(dev_info_t *devi, ddi_detach_cmd_t cmd);
468e50dcc9Sbrutus static int ioat_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg,
478e50dcc9Sbrutus void **result);
48*19397407SSherry Moore static int ioat_quiesce(dev_info_t *dip);
498e50dcc9Sbrutus
508e50dcc9Sbrutus static struct cb_ops ioat_cb_ops = {
518e50dcc9Sbrutus ioat_open, /* cb_open */
528e50dcc9Sbrutus ioat_close, /* cb_close */
538e50dcc9Sbrutus nodev, /* cb_strategy */
548e50dcc9Sbrutus nodev, /* cb_print */
558e50dcc9Sbrutus nodev, /* cb_dump */
568e50dcc9Sbrutus nodev, /* cb_read */
578e50dcc9Sbrutus nodev, /* cb_write */
588e50dcc9Sbrutus ioat_ioctl, /* cb_ioctl */
598e50dcc9Sbrutus nodev, /* cb_devmap */
608e50dcc9Sbrutus nodev, /* cb_mmap */
618e50dcc9Sbrutus nodev, /* cb_segmap */
628e50dcc9Sbrutus nochpoll, /* cb_chpoll */
638e50dcc9Sbrutus ddi_prop_op, /* cb_prop_op */
648e50dcc9Sbrutus NULL, /* cb_stream */
658e50dcc9Sbrutus D_NEW | D_MP | D_64BIT | D_DEVMAP, /* cb_flag */
668e50dcc9Sbrutus CB_REV
678e50dcc9Sbrutus };
688e50dcc9Sbrutus
698e50dcc9Sbrutus static struct dev_ops ioat_dev_ops = {
708e50dcc9Sbrutus DEVO_REV, /* devo_rev */
718e50dcc9Sbrutus 0, /* devo_refcnt */
728e50dcc9Sbrutus ioat_getinfo, /* devo_getinfo */
738e50dcc9Sbrutus nulldev, /* devo_identify */
748e50dcc9Sbrutus nulldev, /* devo_probe */
758e50dcc9Sbrutus ioat_attach, /* devo_attach */
768e50dcc9Sbrutus ioat_detach, /* devo_detach */
778e50dcc9Sbrutus nodev, /* devo_reset */
788e50dcc9Sbrutus &ioat_cb_ops, /* devo_cb_ops */
798e50dcc9Sbrutus NULL, /* devo_bus_ops */
80*19397407SSherry Moore NULL, /* devo_power */
81*19397407SSherry Moore ioat_quiesce, /* devo_quiesce */
828e50dcc9Sbrutus };
838e50dcc9Sbrutus
848e50dcc9Sbrutus static struct modldrv ioat_modldrv = {
858e50dcc9Sbrutus &mod_driverops, /* Type of module. This one is a driver */
86613b2871SRichard Bean "ioat driver", /* Name of the module. */
878e50dcc9Sbrutus &ioat_dev_ops, /* driver ops */
888e50dcc9Sbrutus };
898e50dcc9Sbrutus
908e50dcc9Sbrutus static struct modlinkage ioat_modlinkage = {
918e50dcc9Sbrutus MODREV_1,
928e50dcc9Sbrutus (void *) &ioat_modldrv,
938e50dcc9Sbrutus NULL
948e50dcc9Sbrutus };
958e50dcc9Sbrutus
968e50dcc9Sbrutus
978e50dcc9Sbrutus void *ioat_statep;
988e50dcc9Sbrutus
998e50dcc9Sbrutus static int ioat_chip_init(ioat_state_t *state);
1008e50dcc9Sbrutus static void ioat_chip_fini(ioat_state_t *state);
1018e50dcc9Sbrutus static int ioat_drv_init(ioat_state_t *state);
1028e50dcc9Sbrutus static void ioat_drv_fini(ioat_state_t *state);
1038e50dcc9Sbrutus static uint_t ioat_isr(caddr_t parm);
1048e50dcc9Sbrutus static void ioat_intr_enable(ioat_state_t *state);
1058e50dcc9Sbrutus static void ioat_intr_disable(ioat_state_t *state);
1068e50dcc9Sbrutus void ioat_detach_finish(ioat_state_t *state);
1078e50dcc9Sbrutus
1088e50dcc9Sbrutus
1098e50dcc9Sbrutus ddi_device_acc_attr_t ioat_acc_attr = {
1108e50dcc9Sbrutus DDI_DEVICE_ATTR_V0, /* devacc_attr_version */
1118e50dcc9Sbrutus DDI_NEVERSWAP_ACC, /* devacc_attr_endian_flags */
1128e50dcc9Sbrutus DDI_STORECACHING_OK_ACC, /* devacc_attr_dataorder */
1138e50dcc9Sbrutus DDI_DEFAULT_ACC /* devacc_attr_access */
1148e50dcc9Sbrutus };
1158e50dcc9Sbrutus
1168e50dcc9Sbrutus /* dcopy callback interface */
1178e50dcc9Sbrutus dcopy_device_cb_t ioat_cb = {
1188e50dcc9Sbrutus DCOPY_DEVICECB_V0,
1198e50dcc9Sbrutus 0, /* reserved */
1208e50dcc9Sbrutus ioat_channel_alloc,
1218e50dcc9Sbrutus ioat_channel_free,
1228e50dcc9Sbrutus ioat_cmd_alloc,
1238e50dcc9Sbrutus ioat_cmd_free,
1248e50dcc9Sbrutus ioat_cmd_post,
1258e50dcc9Sbrutus ioat_cmd_poll,
1268e50dcc9Sbrutus ioat_unregister_complete
1278e50dcc9Sbrutus };
1288e50dcc9Sbrutus
1298e50dcc9Sbrutus /*
1308e50dcc9Sbrutus * _init()
1318e50dcc9Sbrutus */
1328e50dcc9Sbrutus int
_init(void)1338e50dcc9Sbrutus _init(void)
1348e50dcc9Sbrutus {
1358e50dcc9Sbrutus int e;
1368e50dcc9Sbrutus
1378e50dcc9Sbrutus e = ddi_soft_state_init(&ioat_statep, sizeof (ioat_state_t), 1);
1388e50dcc9Sbrutus if (e != 0) {
1398e50dcc9Sbrutus return (e);
1408e50dcc9Sbrutus }
1418e50dcc9Sbrutus
1428e50dcc9Sbrutus e = mod_install(&ioat_modlinkage);
1438e50dcc9Sbrutus if (e != 0) {
1448e50dcc9Sbrutus ddi_soft_state_fini(&ioat_statep);
1458e50dcc9Sbrutus return (e);
1468e50dcc9Sbrutus }
1478e50dcc9Sbrutus
1488e50dcc9Sbrutus return (0);
1498e50dcc9Sbrutus }
1508e50dcc9Sbrutus
1518e50dcc9Sbrutus /*
1528e50dcc9Sbrutus * _info()
1538e50dcc9Sbrutus */
1548e50dcc9Sbrutus int
_info(struct modinfo * modinfop)1558e50dcc9Sbrutus _info(struct modinfo *modinfop)
1568e50dcc9Sbrutus {
1578e50dcc9Sbrutus return (mod_info(&ioat_modlinkage, modinfop));
1588e50dcc9Sbrutus }
1598e50dcc9Sbrutus
1608e50dcc9Sbrutus /*
1618e50dcc9Sbrutus * _fini()
1628e50dcc9Sbrutus */
1638e50dcc9Sbrutus int
_fini(void)1648e50dcc9Sbrutus _fini(void)
1658e50dcc9Sbrutus {
1668e50dcc9Sbrutus int e;
1678e50dcc9Sbrutus
1688e50dcc9Sbrutus e = mod_remove(&ioat_modlinkage);
1698e50dcc9Sbrutus if (e != 0) {
1708e50dcc9Sbrutus return (e);
1718e50dcc9Sbrutus }
1728e50dcc9Sbrutus
1738e50dcc9Sbrutus ddi_soft_state_fini(&ioat_statep);
1748e50dcc9Sbrutus
1758e50dcc9Sbrutus return (0);
1768e50dcc9Sbrutus }
1778e50dcc9Sbrutus
1788e50dcc9Sbrutus /*
1798e50dcc9Sbrutus * ioat_attach()
1808e50dcc9Sbrutus */
1818e50dcc9Sbrutus static int
ioat_attach(dev_info_t * dip,ddi_attach_cmd_t cmd)1828e50dcc9Sbrutus ioat_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
1838e50dcc9Sbrutus {
1848e50dcc9Sbrutus ioat_state_t *state;
1858e50dcc9Sbrutus int instance;
1868e50dcc9Sbrutus int e;
1878e50dcc9Sbrutus
1888e50dcc9Sbrutus
1898e50dcc9Sbrutus switch (cmd) {
1908e50dcc9Sbrutus case DDI_ATTACH:
1918e50dcc9Sbrutus break;
1928e50dcc9Sbrutus
1938e50dcc9Sbrutus case DDI_RESUME:
1948e50dcc9Sbrutus instance = ddi_get_instance(dip);
1958e50dcc9Sbrutus state = ddi_get_soft_state(ioat_statep, instance);
1968e50dcc9Sbrutus if (state == NULL) {
1978e50dcc9Sbrutus return (DDI_FAILURE);
1988e50dcc9Sbrutus }
1998e50dcc9Sbrutus e = ioat_channel_resume(state);
2008e50dcc9Sbrutus if (e != DDI_SUCCESS) {
2018e50dcc9Sbrutus return (DDI_FAILURE);
2028e50dcc9Sbrutus }
2038e50dcc9Sbrutus ioat_intr_enable(state);
2048e50dcc9Sbrutus return (DDI_SUCCESS);
2058e50dcc9Sbrutus
2068e50dcc9Sbrutus default:
2078e50dcc9Sbrutus return (DDI_FAILURE);
2088e50dcc9Sbrutus }
2098e50dcc9Sbrutus
2108e50dcc9Sbrutus instance = ddi_get_instance(dip);
2118e50dcc9Sbrutus e = ddi_soft_state_zalloc(ioat_statep, instance);
2128e50dcc9Sbrutus if (e != DDI_SUCCESS) {
2138e50dcc9Sbrutus return (DDI_FAILURE);
2148e50dcc9Sbrutus }
2158e50dcc9Sbrutus state = ddi_get_soft_state(ioat_statep, instance);
2168e50dcc9Sbrutus if (state == NULL) {
2178e50dcc9Sbrutus goto attachfail_get_soft_state;
2188e50dcc9Sbrutus }
2198e50dcc9Sbrutus
2208e50dcc9Sbrutus state->is_dip = dip;
2218e50dcc9Sbrutus state->is_instance = instance;
2228e50dcc9Sbrutus
2238e50dcc9Sbrutus /* setup the registers, save away some device info */
2248e50dcc9Sbrutus e = ioat_chip_init(state);
2258e50dcc9Sbrutus if (e != DDI_SUCCESS) {
2268e50dcc9Sbrutus goto attachfail_chip_init;
2278e50dcc9Sbrutus }
2288e50dcc9Sbrutus
2298e50dcc9Sbrutus /* initialize driver state, must be after chip init */
2308e50dcc9Sbrutus e = ioat_drv_init(state);
2318e50dcc9Sbrutus if (e != DDI_SUCCESS) {
2328e50dcc9Sbrutus goto attachfail_drv_init;
2338e50dcc9Sbrutus }
2348e50dcc9Sbrutus
2358e50dcc9Sbrutus /* create the minor node (for the ioctl) */
2368e50dcc9Sbrutus e = ddi_create_minor_node(dip, "ioat", S_IFCHR, instance, DDI_PSEUDO,
2378e50dcc9Sbrutus 0);
2388e50dcc9Sbrutus if (e != DDI_SUCCESS) {
2398e50dcc9Sbrutus goto attachfail_minor_node;
2408e50dcc9Sbrutus }
2418e50dcc9Sbrutus
2428e50dcc9Sbrutus /* Enable device interrupts */
2438e50dcc9Sbrutus ioat_intr_enable(state);
2448e50dcc9Sbrutus
2458e50dcc9Sbrutus /* Report that driver was loaded */
2468e50dcc9Sbrutus ddi_report_dev(dip);
2478e50dcc9Sbrutus
2488e50dcc9Sbrutus /* register with dcopy */
2498e50dcc9Sbrutus e = dcopy_device_register(state, &state->is_deviceinfo,
2508e50dcc9Sbrutus &state->is_device_handle);
2518e50dcc9Sbrutus if (e != DCOPY_SUCCESS) {
2528e50dcc9Sbrutus goto attachfail_register;
2538e50dcc9Sbrutus }
2548e50dcc9Sbrutus
2558e50dcc9Sbrutus return (DDI_SUCCESS);
2568e50dcc9Sbrutus
2578e50dcc9Sbrutus attachfail_register:
2588e50dcc9Sbrutus ioat_intr_disable(state);
2598e50dcc9Sbrutus ddi_remove_minor_node(dip, NULL);
2608e50dcc9Sbrutus attachfail_minor_node:
2618e50dcc9Sbrutus ioat_drv_fini(state);
2628e50dcc9Sbrutus attachfail_drv_init:
2638e50dcc9Sbrutus ioat_chip_fini(state);
2648e50dcc9Sbrutus attachfail_chip_init:
2658e50dcc9Sbrutus attachfail_get_soft_state:
2668e50dcc9Sbrutus (void) ddi_soft_state_free(ioat_statep, instance);
2678e50dcc9Sbrutus
2688e50dcc9Sbrutus return (DDI_FAILURE);
2698e50dcc9Sbrutus }
2708e50dcc9Sbrutus
2718e50dcc9Sbrutus /*
2728e50dcc9Sbrutus * ioat_detach()
2738e50dcc9Sbrutus */
2748e50dcc9Sbrutus static int
ioat_detach(dev_info_t * dip,ddi_detach_cmd_t cmd)2758e50dcc9Sbrutus ioat_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
2768e50dcc9Sbrutus {
2778e50dcc9Sbrutus ioat_state_t *state;
2788e50dcc9Sbrutus int instance;
2798e50dcc9Sbrutus int e;
2808e50dcc9Sbrutus
2818e50dcc9Sbrutus
2828e50dcc9Sbrutus instance = ddi_get_instance(dip);
2838e50dcc9Sbrutus state = ddi_get_soft_state(ioat_statep, instance);
2848e50dcc9Sbrutus if (state == NULL) {
2858e50dcc9Sbrutus return (DDI_FAILURE);
2868e50dcc9Sbrutus }
2878e50dcc9Sbrutus
2888e50dcc9Sbrutus switch (cmd) {
2898e50dcc9Sbrutus case DDI_DETACH:
2908e50dcc9Sbrutus break;
2918e50dcc9Sbrutus
2928e50dcc9Sbrutus case DDI_SUSPEND:
2938e50dcc9Sbrutus ioat_channel_suspend(state);
2948e50dcc9Sbrutus return (DDI_SUCCESS);
2958e50dcc9Sbrutus
2968e50dcc9Sbrutus default:
2978e50dcc9Sbrutus return (DDI_FAILURE);
2988e50dcc9Sbrutus }
2998e50dcc9Sbrutus
3008e50dcc9Sbrutus /*
3018e50dcc9Sbrutus * try to unregister from dcopy. Since this driver doesn't follow the
3028e50dcc9Sbrutus * traditional parent/child model, we may still be in use so we can't
3038e50dcc9Sbrutus * detach yet.
3048e50dcc9Sbrutus */
3058e50dcc9Sbrutus e = dcopy_device_unregister(&state->is_device_handle);
3068e50dcc9Sbrutus if (e != DCOPY_SUCCESS) {
3078e50dcc9Sbrutus if (e == DCOPY_PENDING) {
3088e50dcc9Sbrutus cmn_err(CE_NOTE, "device busy, performing asynchronous"
3098e50dcc9Sbrutus " detach\n");
3108e50dcc9Sbrutus }
3118e50dcc9Sbrutus return (DDI_FAILURE);
3128e50dcc9Sbrutus }
3138e50dcc9Sbrutus
3148e50dcc9Sbrutus ioat_detach_finish(state);
3158e50dcc9Sbrutus
3168e50dcc9Sbrutus return (DDI_SUCCESS);
3178e50dcc9Sbrutus }
3188e50dcc9Sbrutus
3198e50dcc9Sbrutus /*
3208e50dcc9Sbrutus * ioat_getinfo()
3218e50dcc9Sbrutus */
3228e50dcc9Sbrutus /*ARGSUSED*/
3238e50dcc9Sbrutus static int
ioat_getinfo(dev_info_t * dip,ddi_info_cmd_t cmd,void * arg,void ** result)3248e50dcc9Sbrutus ioat_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **result)
3258e50dcc9Sbrutus {
3268e50dcc9Sbrutus ioat_state_t *state;
3278e50dcc9Sbrutus int instance;
3288e50dcc9Sbrutus dev_t dev;
3298e50dcc9Sbrutus int e;
3308e50dcc9Sbrutus
3318e50dcc9Sbrutus
3328e50dcc9Sbrutus dev = (dev_t)arg;
3338e50dcc9Sbrutus instance = getminor(dev);
3348e50dcc9Sbrutus
3358e50dcc9Sbrutus switch (cmd) {
3368e50dcc9Sbrutus case DDI_INFO_DEVT2DEVINFO:
3378e50dcc9Sbrutus state = ddi_get_soft_state(ioat_statep, instance);
3388e50dcc9Sbrutus if (state == NULL) {
3398e50dcc9Sbrutus return (DDI_FAILURE);
3408e50dcc9Sbrutus }
3418e50dcc9Sbrutus *result = (void *)state->is_dip;
3428e50dcc9Sbrutus e = DDI_SUCCESS;
3438e50dcc9Sbrutus break;
3448e50dcc9Sbrutus
3458e50dcc9Sbrutus case DDI_INFO_DEVT2INSTANCE:
3468e50dcc9Sbrutus *result = (void *)(uintptr_t)instance;
3478e50dcc9Sbrutus e = DDI_SUCCESS;
3488e50dcc9Sbrutus break;
3498e50dcc9Sbrutus
3508e50dcc9Sbrutus default:
3518e50dcc9Sbrutus e = DDI_FAILURE;
3528e50dcc9Sbrutus break;
3538e50dcc9Sbrutus }
3548e50dcc9Sbrutus
3558e50dcc9Sbrutus return (e);
3568e50dcc9Sbrutus }
3578e50dcc9Sbrutus
3588e50dcc9Sbrutus
3598e50dcc9Sbrutus /*
3608e50dcc9Sbrutus * ioat_open()
3618e50dcc9Sbrutus */
3628e50dcc9Sbrutus /*ARGSUSED*/
3638e50dcc9Sbrutus static int
ioat_open(dev_t * devp,int flag,int otyp,cred_t * cred)3648e50dcc9Sbrutus ioat_open(dev_t *devp, int flag, int otyp, cred_t *cred)
3658e50dcc9Sbrutus {
3668e50dcc9Sbrutus ioat_state_t *state;
3678e50dcc9Sbrutus int instance;
3688e50dcc9Sbrutus
3698e50dcc9Sbrutus instance = getminor(*devp);
3708e50dcc9Sbrutus state = ddi_get_soft_state(ioat_statep, instance);
3718e50dcc9Sbrutus if (state == NULL) {
3728e50dcc9Sbrutus return (ENXIO);
3738e50dcc9Sbrutus }
3748e50dcc9Sbrutus
3758e50dcc9Sbrutus return (0);
3768e50dcc9Sbrutus }
3778e50dcc9Sbrutus
3788e50dcc9Sbrutus
3798e50dcc9Sbrutus /*
3808e50dcc9Sbrutus * ioat_close()
3818e50dcc9Sbrutus */
3828e50dcc9Sbrutus /*ARGSUSED*/
3838e50dcc9Sbrutus static int
ioat_close(dev_t devp,int flag,int otyp,cred_t * cred)3848e50dcc9Sbrutus ioat_close(dev_t devp, int flag, int otyp, cred_t *cred)
3858e50dcc9Sbrutus {
3868e50dcc9Sbrutus return (0);
3878e50dcc9Sbrutus }
3888e50dcc9Sbrutus
3898e50dcc9Sbrutus
3908e50dcc9Sbrutus /*
3918e50dcc9Sbrutus * ioat_chip_init()
3928e50dcc9Sbrutus */
3938e50dcc9Sbrutus static int
ioat_chip_init(ioat_state_t * state)3948e50dcc9Sbrutus ioat_chip_init(ioat_state_t *state)
3958e50dcc9Sbrutus {
3968e50dcc9Sbrutus ddi_device_acc_attr_t attr;
3978e50dcc9Sbrutus int e;
3988e50dcc9Sbrutus
3998e50dcc9Sbrutus
4008e50dcc9Sbrutus attr.devacc_attr_version = DDI_DEVICE_ATTR_V0;
4018e50dcc9Sbrutus attr.devacc_attr_endian_flags = DDI_NEVERSWAP_ACC;
4028e50dcc9Sbrutus attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC;
4038e50dcc9Sbrutus
4048e50dcc9Sbrutus e = ddi_regs_map_setup(state->is_dip, 1, (caddr_t *)&state->is_genregs,
4058e50dcc9Sbrutus 0, 0, &attr, &state->is_reg_handle);
4068e50dcc9Sbrutus if (e != DDI_SUCCESS) {
4078e50dcc9Sbrutus goto chipinitfail_regsmap;
4088e50dcc9Sbrutus }
4098e50dcc9Sbrutus
4108e50dcc9Sbrutus /* save away ioat chip info */
4118e50dcc9Sbrutus state->is_num_channels = (uint_t)ddi_get8(state->is_reg_handle,
4128e50dcc9Sbrutus &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
4228e50dcc9Sbrutus state->is_maxxfer = (uint_t)ddi_get8(state->is_reg_handle,
4238e50dcc9Sbrutus &state->is_genregs[IOAT_XFERCAP]);
4248e50dcc9Sbrutus state->is_chanoff = (uintptr_t)ddi_get16(state->is_reg_handle,
4258e50dcc9Sbrutus (uint16_t *)&state->is_genregs[IOAT_PERPORT_OFF]);
4268e50dcc9Sbrutus state->is_cbver = (uint_t)ddi_get8(state->is_reg_handle,
4278e50dcc9Sbrutus &state->is_genregs[IOAT_CBVER]);
4288e50dcc9Sbrutus state->is_intrdelay = (uint_t)ddi_get16(state->is_reg_handle,
4298e50dcc9Sbrutus (uint16_t *)&state->is_genregs[IOAT_INTRDELAY]);
4308e50dcc9Sbrutus state->is_status = (uint_t)ddi_get16(state->is_reg_handle,
4318e50dcc9Sbrutus (uint16_t *)&state->is_genregs[IOAT_CSSTATUS]);
4328e50dcc9Sbrutus state->is_capabilities = (uint_t)ddi_get32(state->is_reg_handle,
4338e50dcc9Sbrutus (uint32_t *)&state->is_genregs[IOAT_DMACAPABILITY]);
4348e50dcc9Sbrutus
4358e50dcc9Sbrutus if (state->is_cbver & 0x10) {
4368e50dcc9Sbrutus state->is_ver = IOAT_CBv1;
4378e50dcc9Sbrutus } else if (state->is_cbver & 0x20) {
4388e50dcc9Sbrutus state->is_ver = IOAT_CBv2;
4398e50dcc9Sbrutus } else {
4408e50dcc9Sbrutus goto chipinitfail_version;
4418e50dcc9Sbrutus }
4428e50dcc9Sbrutus
4438e50dcc9Sbrutus return (DDI_SUCCESS);
4448e50dcc9Sbrutus
4458e50dcc9Sbrutus chipinitfail_version:
446e6beb20cSmrj chipinitfail_numchan:
4478e50dcc9Sbrutus ddi_regs_map_free(&state->is_reg_handle);
4488e50dcc9Sbrutus chipinitfail_regsmap:
4498e50dcc9Sbrutus return (DDI_FAILURE);
4508e50dcc9Sbrutus }
4518e50dcc9Sbrutus
4528e50dcc9Sbrutus
4538e50dcc9Sbrutus /*
4548e50dcc9Sbrutus * ioat_chip_fini()
4558e50dcc9Sbrutus */
4568e50dcc9Sbrutus static void
ioat_chip_fini(ioat_state_t * state)4578e50dcc9Sbrutus ioat_chip_fini(ioat_state_t *state)
4588e50dcc9Sbrutus {
4598e50dcc9Sbrutus ddi_regs_map_free(&state->is_reg_handle);
4608e50dcc9Sbrutus }
4618e50dcc9Sbrutus
4628e50dcc9Sbrutus
4638e50dcc9Sbrutus /*
4648e50dcc9Sbrutus * ioat_drv_init()
4658e50dcc9Sbrutus */
4668e50dcc9Sbrutus static int
ioat_drv_init(ioat_state_t * state)4678e50dcc9Sbrutus ioat_drv_init(ioat_state_t *state)
4688e50dcc9Sbrutus {
4698e50dcc9Sbrutus ddi_acc_handle_t handle;
4708e50dcc9Sbrutus int e;
4718e50dcc9Sbrutus
4728e50dcc9Sbrutus
4738e50dcc9Sbrutus mutex_init(&state->is_mutex, NULL, MUTEX_DRIVER, NULL);
4748e50dcc9Sbrutus
4758e50dcc9Sbrutus state->is_deviceinfo.di_dip = state->is_dip;
4768e50dcc9Sbrutus state->is_deviceinfo.di_num_dma = state->is_num_channels;
4778e50dcc9Sbrutus state->is_deviceinfo.di_maxxfer = state->is_maxxfer;
4788e50dcc9Sbrutus state->is_deviceinfo.di_capabilities = state->is_capabilities;
4798e50dcc9Sbrutus state->is_deviceinfo.di_cb = &ioat_cb;
4808e50dcc9Sbrutus
4818e50dcc9Sbrutus e = pci_config_setup(state->is_dip, &handle);
4828e50dcc9Sbrutus if (e != DDI_SUCCESS) {
4838e50dcc9Sbrutus goto drvinitfail_config_setup;
4848e50dcc9Sbrutus }
4858e50dcc9Sbrutus
4868e50dcc9Sbrutus /* read in Vendor ID */
4878e50dcc9Sbrutus state->is_deviceinfo.di_id = (uint64_t)pci_config_get16(handle, 0);
4888e50dcc9Sbrutus state->is_deviceinfo.di_id = state->is_deviceinfo.di_id << 16;
4898e50dcc9Sbrutus
4908e50dcc9Sbrutus /* read in Device ID */
4918e50dcc9Sbrutus state->is_deviceinfo.di_id |= (uint64_t)pci_config_get16(handle, 2);
4928e50dcc9Sbrutus state->is_deviceinfo.di_id = state->is_deviceinfo.di_id << 32;
4938e50dcc9Sbrutus
4948e50dcc9Sbrutus /* Add in chipset version */
4958e50dcc9Sbrutus state->is_deviceinfo.di_id |= (uint64_t)state->is_cbver;
4968e50dcc9Sbrutus pci_config_teardown(&handle);
4978e50dcc9Sbrutus
4988e50dcc9Sbrutus e = ddi_intr_hilevel(state->is_dip, 0);
4998e50dcc9Sbrutus if (e != 0) {
5008e50dcc9Sbrutus cmn_err(CE_WARN, "hilevel interrupt not supported\n");
5018e50dcc9Sbrutus goto drvinitfail_hilevel;
5028e50dcc9Sbrutus }
5038e50dcc9Sbrutus
5048e50dcc9Sbrutus /* we don't support MSIs for v2 yet */
5058e50dcc9Sbrutus e = ddi_add_intr(state->is_dip, 0, NULL, NULL, ioat_isr,
5068e50dcc9Sbrutus (caddr_t)state);
5078e50dcc9Sbrutus if (e != DDI_SUCCESS) {
5088e50dcc9Sbrutus goto drvinitfail_add_intr;
5098e50dcc9Sbrutus }
5108e50dcc9Sbrutus
5118e50dcc9Sbrutus e = ddi_get_iblock_cookie(state->is_dip, 0, &state->is_iblock_cookie);
5128e50dcc9Sbrutus if (e != DDI_SUCCESS) {
5138e50dcc9Sbrutus goto drvinitfail_iblock_cookie;
5148e50dcc9Sbrutus }
5158e50dcc9Sbrutus
5168e50dcc9Sbrutus e = ioat_channel_init(state);
5178e50dcc9Sbrutus if (e != DDI_SUCCESS) {
5188e50dcc9Sbrutus goto drvinitfail_channel_init;
5198e50dcc9Sbrutus }
5208e50dcc9Sbrutus
5218e50dcc9Sbrutus return (DDI_SUCCESS);
5228e50dcc9Sbrutus
5238e50dcc9Sbrutus drvinitfail_channel_init:
5248e50dcc9Sbrutus drvinitfail_iblock_cookie:
5258e50dcc9Sbrutus ddi_remove_intr(state->is_dip, 0, state->is_iblock_cookie);
5268e50dcc9Sbrutus drvinitfail_add_intr:
5278e50dcc9Sbrutus drvinitfail_hilevel:
5288e50dcc9Sbrutus drvinitfail_config_setup:
5298e50dcc9Sbrutus mutex_destroy(&state->is_mutex);
5308e50dcc9Sbrutus
5318e50dcc9Sbrutus return (DDI_FAILURE);
5328e50dcc9Sbrutus }
5338e50dcc9Sbrutus
5348e50dcc9Sbrutus
5358e50dcc9Sbrutus /*
5368e50dcc9Sbrutus * ioat_drv_fini()
5378e50dcc9Sbrutus */
5388e50dcc9Sbrutus static void
ioat_drv_fini(ioat_state_t * state)5398e50dcc9Sbrutus ioat_drv_fini(ioat_state_t *state)
5408e50dcc9Sbrutus {
5418e50dcc9Sbrutus ioat_channel_fini(state);
5428e50dcc9Sbrutus ddi_remove_intr(state->is_dip, 0, state->is_iblock_cookie);
5438e50dcc9Sbrutus mutex_destroy(&state->is_mutex);
5448e50dcc9Sbrutus }
5458e50dcc9Sbrutus
5468e50dcc9Sbrutus
5478e50dcc9Sbrutus /*
5488e50dcc9Sbrutus * ioat_unregister_complete()
5498e50dcc9Sbrutus */
5508e50dcc9Sbrutus void
ioat_unregister_complete(void * device_private,int status)5518e50dcc9Sbrutus ioat_unregister_complete(void *device_private, int status)
5528e50dcc9Sbrutus {
5538e50dcc9Sbrutus ioat_state_t *state;
5548e50dcc9Sbrutus
5558e50dcc9Sbrutus
5568e50dcc9Sbrutus state = device_private;
5578e50dcc9Sbrutus
5588e50dcc9Sbrutus if (status != DCOPY_SUCCESS) {
5598e50dcc9Sbrutus cmn_err(CE_WARN, "asynchronous detach aborted\n");
5608e50dcc9Sbrutus return;
5618e50dcc9Sbrutus }
5628e50dcc9Sbrutus
5638e50dcc9Sbrutus cmn_err(CE_CONT, "detach completing\n");
5648e50dcc9Sbrutus ioat_detach_finish(state);
5658e50dcc9Sbrutus }
5668e50dcc9Sbrutus
5678e50dcc9Sbrutus
5688e50dcc9Sbrutus /*
5698e50dcc9Sbrutus * ioat_detach_finish()
5708e50dcc9Sbrutus */
5718e50dcc9Sbrutus void
ioat_detach_finish(ioat_state_t * state)5728e50dcc9Sbrutus ioat_detach_finish(ioat_state_t *state)
5738e50dcc9Sbrutus {
5748e50dcc9Sbrutus ioat_intr_disable(state);
5758e50dcc9Sbrutus ddi_remove_minor_node(state->is_dip, NULL);
5768e50dcc9Sbrutus ioat_drv_fini(state);
5778e50dcc9Sbrutus ioat_chip_fini(state);
5788e50dcc9Sbrutus (void) ddi_soft_state_free(ioat_statep, state->is_instance);
5798e50dcc9Sbrutus }
5808e50dcc9Sbrutus
5818e50dcc9Sbrutus
5828e50dcc9Sbrutus /*
5838e50dcc9Sbrutus * ioat_intr_enable()
5848e50dcc9Sbrutus */
5858e50dcc9Sbrutus static void
ioat_intr_enable(ioat_state_t * state)5868e50dcc9Sbrutus ioat_intr_enable(ioat_state_t *state)
5878e50dcc9Sbrutus {
5888e50dcc9Sbrutus uint32_t intr_status;
5898e50dcc9Sbrutus
5908e50dcc9Sbrutus
5918e50dcc9Sbrutus /* Clear any pending interrupts */
5928e50dcc9Sbrutus intr_status = ddi_get32(state->is_reg_handle,
5938e50dcc9Sbrutus (uint32_t *)&state->is_genregs[IOAT_ATTNSTATUS]);
5948e50dcc9Sbrutus if (intr_status != 0) {
5958e50dcc9Sbrutus ddi_put32(state->is_reg_handle,
5968e50dcc9Sbrutus (uint32_t *)&state->is_genregs[IOAT_ATTNSTATUS],
5978e50dcc9Sbrutus intr_status);
5988e50dcc9Sbrutus }
5998e50dcc9Sbrutus
6008e50dcc9Sbrutus /* Enable interrupts on the device */
6018e50dcc9Sbrutus ddi_put8(state->is_reg_handle, &state->is_genregs[IOAT_INTRCTL],
6028e50dcc9Sbrutus IOAT_INTRCTL_MASTER_EN);
6038e50dcc9Sbrutus }
6048e50dcc9Sbrutus
6058e50dcc9Sbrutus
6068e50dcc9Sbrutus /*
6078e50dcc9Sbrutus * ioat_intr_disable()
6088e50dcc9Sbrutus */
6098e50dcc9Sbrutus static void
ioat_intr_disable(ioat_state_t * state)6108e50dcc9Sbrutus ioat_intr_disable(ioat_state_t *state)
6118e50dcc9Sbrutus {
6128e50dcc9Sbrutus /*
6138e50dcc9Sbrutus * disable interrupts on the device. A read of the interrupt control
6148e50dcc9Sbrutus * register clears the enable bit.
6158e50dcc9Sbrutus */
6168e50dcc9Sbrutus (void) ddi_get8(state->is_reg_handle,
6178e50dcc9Sbrutus &state->is_genregs[IOAT_INTRCTL]);
6188e50dcc9Sbrutus }
6198e50dcc9Sbrutus
6208e50dcc9Sbrutus
6218e50dcc9Sbrutus /*
6228e50dcc9Sbrutus * ioat_isr()
6238e50dcc9Sbrutus */
6248e50dcc9Sbrutus static uint_t
ioat_isr(caddr_t parm)6258e50dcc9Sbrutus ioat_isr(caddr_t parm)
6268e50dcc9Sbrutus {
6278e50dcc9Sbrutus uint32_t intr_status;
6288e50dcc9Sbrutus ioat_state_t *state;
6298e50dcc9Sbrutus uint8_t intrctrl;
6308e50dcc9Sbrutus uint32_t chan;
6318e50dcc9Sbrutus uint_t r;
6328e50dcc9Sbrutus int i;
6338e50dcc9Sbrutus
6348e50dcc9Sbrutus state = (ioat_state_t *)parm;
6358e50dcc9Sbrutus
6368e50dcc9Sbrutus intrctrl = ddi_get8(state->is_reg_handle,
6378e50dcc9Sbrutus &state->is_genregs[IOAT_INTRCTL]);
6388e50dcc9Sbrutus /* master interrupt enable should always be set */
6398e50dcc9Sbrutus ASSERT(intrctrl & IOAT_INTRCTL_MASTER_EN);
6408e50dcc9Sbrutus
6418e50dcc9Sbrutus /* If the interrupt status bit isn't set, it's not ours */
6428e50dcc9Sbrutus if (!(intrctrl & IOAT_INTRCTL_INTR_STAT)) {
6438e50dcc9Sbrutus /* re-set master interrupt enable (since it clears on read) */
6448e50dcc9Sbrutus ddi_put8(state->is_reg_handle,
6458e50dcc9Sbrutus &state->is_genregs[IOAT_INTRCTL], intrctrl);
6468e50dcc9Sbrutus return (DDI_INTR_UNCLAIMED);
6478e50dcc9Sbrutus }
6488e50dcc9Sbrutus
6498e50dcc9Sbrutus /* see which channels generated the interrupt */
6508e50dcc9Sbrutus intr_status = ddi_get32(state->is_reg_handle,
6518e50dcc9Sbrutus (uint32_t *)&state->is_genregs[IOAT_ATTNSTATUS]);
6528e50dcc9Sbrutus
6538e50dcc9Sbrutus /* call the intr handler for the channels */
6548e50dcc9Sbrutus r = DDI_INTR_UNCLAIMED;
6558e50dcc9Sbrutus chan = 1;
6568e50dcc9Sbrutus for (i = 0; i < state->is_num_channels; i++) {
6578e50dcc9Sbrutus if (intr_status & chan) {
6588e50dcc9Sbrutus ioat_channel_intr(&state->is_channel[i]);
6598e50dcc9Sbrutus r = DDI_INTR_CLAIMED;
6608e50dcc9Sbrutus }
6618e50dcc9Sbrutus chan = chan << 1;
6628e50dcc9Sbrutus }
6638e50dcc9Sbrutus
6648e50dcc9Sbrutus /*
6658e50dcc9Sbrutus * if interrupt status bit was set, there should have been an
6668e50dcc9Sbrutus * attention status bit set too.
6678e50dcc9Sbrutus */
6688e50dcc9Sbrutus ASSERT(r == DDI_INTR_CLAIMED);
6698e50dcc9Sbrutus
6708e50dcc9Sbrutus /* re-set master interrupt enable (since it clears on read) */
6718e50dcc9Sbrutus ddi_put8(state->is_reg_handle, &state->is_genregs[IOAT_INTRCTL],
6728e50dcc9Sbrutus intrctrl);
6738e50dcc9Sbrutus
6748e50dcc9Sbrutus return (r);
6758e50dcc9Sbrutus }
676*19397407SSherry Moore
677*19397407SSherry Moore static int
ioat_quiesce(dev_info_t * dip)678*19397407SSherry Moore ioat_quiesce(dev_info_t *dip)
679*19397407SSherry Moore {
680*19397407SSherry Moore ioat_state_t *state;
681*19397407SSherry Moore int instance;
682*19397407SSherry Moore
683*19397407SSherry Moore instance = ddi_get_instance(dip);
684*19397407SSherry Moore state = ddi_get_soft_state(ioat_statep, instance);
685*19397407SSherry Moore if (state == NULL) {
686*19397407SSherry Moore return (DDI_FAILURE);
687*19397407SSherry Moore }
688*19397407SSherry Moore
689*19397407SSherry Moore ioat_intr_disable(state);
690*19397407SSherry Moore ioat_channel_quiesce(state);
691*19397407SSherry Moore
692*19397407SSherry Moore return (DDI_SUCCESS);
693*19397407SSherry Moore }
694