xref: /titanic_52/usr/src/uts/i86pc/io/ioat/ioat.c (revision e61a481d2b9ca0c0f387e11b15dcabfc982bb464)
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 #pragma ident	"%Z%%M%	%I%	%E% SMI"
28 
29 #include <sys/errno.h>
30 #include <sys/types.h>
31 #include <sys/conf.h>
32 #include <sys/kmem.h>
33 #include <sys/ddi.h>
34 #include <sys/stat.h>
35 #include <sys/sunddi.h>
36 #include <sys/file.h>
37 #include <sys/open.h>
38 #include <sys/modctl.h>
39 #include <sys/ddi_impldefs.h>
40 #include <sys/sysmacros.h>
41 
42 #include <sys/ioat.h>
43 
44 static int ioat_open(dev_t *devp, int flag, int otyp, cred_t *cred);
45 static int ioat_close(dev_t devp, int flag, int otyp, cred_t *cred);
46 static int ioat_attach(dev_info_t *devi, ddi_attach_cmd_t cmd);
47 static int ioat_detach(dev_info_t *devi, ddi_detach_cmd_t cmd);
48 static int ioat_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg,
49     void **result);
50 
51 static 	struct cb_ops ioat_cb_ops = {
52 	ioat_open,		/* cb_open */
53 	ioat_close,		/* cb_close */
54 	nodev,			/* cb_strategy */
55 	nodev,			/* cb_print */
56 	nodev,			/* cb_dump */
57 	nodev,			/* cb_read */
58 	nodev,			/* cb_write */
59 	ioat_ioctl,		/* cb_ioctl */
60 	nodev,			/* cb_devmap */
61 	nodev,			/* cb_mmap */
62 	nodev,			/* cb_segmap */
63 	nochpoll,		/* cb_chpoll */
64 	ddi_prop_op,		/* cb_prop_op */
65 	NULL,			/* cb_stream */
66 	D_NEW | D_MP | D_64BIT | D_DEVMAP,	/* cb_flag */
67 	CB_REV
68 };
69 
70 static struct dev_ops ioat_dev_ops = {
71 	DEVO_REV,		/* devo_rev */
72 	0,			/* devo_refcnt */
73 	ioat_getinfo,		/* devo_getinfo */
74 	nulldev,		/* devo_identify */
75 	nulldev,		/* devo_probe */
76 	ioat_attach,		/* devo_attach */
77 	ioat_detach,		/* devo_detach */
78 	nodev,			/* devo_reset */
79 	&ioat_cb_ops,		/* devo_cb_ops */
80 	NULL,			/* devo_bus_ops */
81 	NULL			/* power */
82 };
83 
84 static struct modldrv ioat_modldrv = {
85 	&mod_driverops,		/* Type of module.  This one is a driver */
86 	"ioat driver v%I%",	/* 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