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