xref: /titanic_44/usr/src/uts/intel/io/agpgart/agptarget.c (revision f48205be61a214698b763ff550ab9e657525104c)
1 /*
2  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
3  * Use is subject to license terms.
4  */
5 
6 #pragma ident	"%Z%%M%	%I%	%E% SMI"
7 
8 #include <sys/systm.h>
9 #include <sys/conf.h>
10 #include <sys/modctl.h>
11 #include <sys/file.h>
12 #include <sys/stat.h>
13 #include <sys/ddi.h>
14 #include <sys/sunddi.h>
15 #include <sys/modctl.h>
16 #include <sys/sunldi.h>
17 #include <sys/pci.h>
18 #include <sys/agpgart.h>
19 #include <sys/agp/agpdefs.h>
20 #include <sys/agp/agptarget_io.h>
21 
22 int agptarget_debug_var = 0;
23 #define	TARGETDB_PRINT2(fmt)	if (agptarget_debug_var >= 1) cmn_err fmt
24 #define	INST2NODENUM(inst)	(inst)
25 #define	DEV2INST(dev)		(getminor(dev))
26 
27 typedef struct agp_target_softstate {
28 	dev_info_t		*tsoft_dip;
29 	ddi_acc_handle_t	tsoft_pcihdl;
30 	uint32_t		tsoft_devid;
31 	/* The offset of the ACAPID register */
32 	off_t			tsoft_acaptr;
33 	kmutex_t		tsoft_lock;
34 }agp_target_softstate_t;
35 
36 static void *agptarget_glob_soft_handle;
37 
38 #define	GETSOFTC(instance)	((agp_target_softstate_t *)	\
39     ddi_get_soft_state(agptarget_glob_soft_handle, instance));
40 
41 /*
42  * The AMD8151 bridge is the only supported 64 bit hardware
43  */
44 static int
45 is_64bit_aper(agp_target_softstate_t *softstate)
46 {
47 	return (softstate->tsoft_devid == AMD_BR_8151);
48 }
49 
50 /*
51  * agp_target_cap_find()
52  *
53  * Description:
54  * 	This function searches the linked capability list to find the offset
55  * 	of the AGP capability register. When it was not found, return 0.
56  * 	This works for standard AGP chipsets, but not for some Intel chipsets,
57  * 	like the I830M/I830MP/I852PM/I852GME/I855GME. It will return 0 for
58  * 	these chipsets even if AGP is supported. So the offset of acapid
59  * 	should be set manually in thoses cases.
60  *
61  * Arguments:
62  * 	pci_handle		ddi acc handle of pci config
63  *
64  * Returns:
65  * 	0			No capability pointer register found
66  * 	nexcap			The AGP capability pointer register offset
67  */
68 static off_t
69 agp_target_cap_find(ddi_acc_handle_t pci_handle)
70 {
71 	off_t		nextcap = 0;
72 	uint32_t	ncapid = 0;
73 	uint8_t		value = 0;
74 
75 	/* Check if this device supports the capability pointer */
76 	value = (uint8_t)(pci_config_get16(pci_handle, PCI_CONF_STAT)
77 	    & PCI_CONF_CAP_MASK);
78 
79 	if (!value)
80 		return (0);
81 	/* Get the offset of the first capability pointer from CAPPTR */
82 	nextcap = (off_t)(pci_config_get8(pci_handle, AGP_CONF_CAPPTR));
83 
84 	/* Check the AGP capability from the first capability pointer */
85 	while (nextcap) {
86 		ncapid = pci_config_get32(pci_handle, nextcap);
87 		/*
88 		 * AGP3.0 rev1.0 127  the capid was assigned by the PCI SIG,
89 		 * 845 data sheet page 69
90 		 */
91 		if ((ncapid & PCI_CONF_CAPID_MASK) ==
92 		    AGP_CAP_ID) /* The AGP cap was found */
93 			break;
94 
95 		nextcap = (off_t)((ncapid & PCI_CONF_NCAPID_MASK) >> 8);
96 	}
97 
98 	return (nextcap);
99 
100 }
101 
102 /*
103  * agp_target_get_aperbase()
104  *
105  * Description:
106  * 	This function gets the AGP aperture base address from the AGP target
107  *	register, the AGP aperture base register was programmed by the BIOS.
108  *
109  * Arguments:
110  * 	softstate		driver soft state pointer
111  *
112  * Returns:
113  * 	aper_base 		AGP aperture base address
114  *
115  * Notes:
116  * 	If a 64bit bridge device is available, the AGP aperture base address
117  * 	can be 64 bit.
118  */
119 static uint64_t
120 agp_target_get_apbase(agp_target_softstate_t *softstate)
121 {
122 	uint64_t aper_base;
123 
124 	if (!is_64bit_aper(softstate)) {
125 		aper_base = pci_config_get32(softstate->tsoft_pcihdl,
126 		    AGP_CONF_APERBASE) & AGP_32_APERBASE_MASK;
127 	} else {
128 		aper_base = pci_config_get64(softstate->tsoft_pcihdl,
129 		    AGP_CONF_APERBASE);
130 		/* 32-bit or 64-bit aperbase base pointer */
131 		if ((aper_base & AGP_APER_TYPE_MASK) == 0)
132 			aper_base &= AGP_32_APERBASE_MASK;
133 		else
134 			aper_base &= AGP_64_APERBASE_MASK;
135 	}
136 	return (aper_base);
137 }
138 
139 /*
140  * agp_target_get_apsize()
141  *
142  * Description:
143  * 	This function gets the AGP aperture size by reading the AGP aperture
144  * 	size register.
145  * Arguments:
146  * 	softstate		driver soft state pointer
147  *
148  * Return:
149  * 	size		The AGP aperture size in megabytes
150  * 	0		an unexpected error
151  */
152 static size_t
153 agp_target_get_apsize(agp_target_softstate_t *softstate)
154 {
155 	off_t cap;
156 	uint16_t value;
157 	size_t size, regsize;
158 
159 	ASSERT(softstate->tsoft_acaptr);
160 	cap = softstate->tsoft_acaptr;
161 
162 	if ((softstate->tsoft_devid & VENDOR_ID_MASK) == INTEL_VENDOR_ID) {
163 		/* extend this value to 16 bit for later tests */
164 		value = (uint16_t)pci_config_get8(softstate->tsoft_pcihdl,
165 		    cap + AGP_CONF_APERSIZE) | AGP_APER_SIZE_MASK;
166 	} else {
167 		value = pci_config_get16(softstate->tsoft_pcihdl,
168 		    cap + AGP_CONF_APERSIZE);
169 	}
170 
171 	if (value & AGP_APER_128M_MASK) {
172 		switch (value & AGP_APER_128M_MASK) {
173 			case AGP_APER_4M:
174 				size = 4; /* 4M */
175 				break;
176 			case AGP_APER_8M:
177 				size = 8; /* 8M */
178 				break;
179 			case AGP_APER_16M:
180 				size = 16; /* 16M */
181 				break;
182 			case AGP_APER_32M:
183 				size = 32; /* 32M */
184 				break;
185 			case AGP_APER_64M:
186 				size = 64; /* 64M */
187 				break;
188 			case AGP_APER_128M:
189 				size = 128; /* 128M */
190 				break;
191 			default:
192 				size = 0; /* not true */
193 		}
194 	} else {
195 		switch (value & AGP_APER_4G_MASK) {
196 			case AGP_APER_256M:
197 				size = 256; /* 256 M */
198 				break;
199 			case AGP_APER_512M:
200 				size = 512; /* 512 M */
201 				break;
202 			case AGP_APER_1024M:
203 				size = 1024; /* 1024 M */
204 				break;
205 			case AGP_APER_2048M:
206 				size = 2048; /* 2048 M */
207 				break;
208 			case AGP_APER_4G:
209 				size = 4096; /* 4096 M */
210 				break;
211 			default:
212 				size = 0; /* not true */
213 		}
214 	}
215 	/*
216 	 * In some cases, there is no APSIZE register, so the size value
217 	 * of 256M could be wrong. Check the value by reading the size of
218 	 * the first register which was set in the PCI configuration space.
219 	 */
220 	if (size == 256) {
221 		if (ddi_dev_regsize(softstate->tsoft_dip,
222 		    AGP_TARGET_BAR1, (off_t *)&regsize) == DDI_FAILURE)
223 			return (0);
224 
225 		if (MB2BYTES(size) != regsize) {
226 			TARGETDB_PRINT2((CE_WARN,
227 			    "APSIZE 256M doesn't match regsize %lx",
228 			    regsize));
229 			TARGETDB_PRINT2((CE_WARN, "Use regsize instead"));
230 			size = BYTES2MB(regsize);
231 		}
232 	}
233 
234 	return (size);
235 }
236 
237 static void
238 agp_target_set_gartaddr(agp_target_softstate_t *softstate, uint32_t gartaddr)
239 {
240 	ASSERT(softstate->tsoft_acaptr);
241 
242 	/* Disable the GTLB for Intel chipsets */
243 	pci_config_put16(softstate->tsoft_pcihdl,
244 	    softstate->tsoft_acaptr + AGP_CONF_CONTROL, 0x0000);
245 
246 	pci_config_put32(softstate->tsoft_pcihdl,
247 	    softstate->tsoft_acaptr + AGP_CONF_ATTBASE,
248 	    gartaddr & AGP_ATTBASE_MASK);
249 }
250 
251 static size_t
252 i8xx_biosmem_detect(agp_target_softstate_t *softstate)
253 {
254 	uint8_t memval;
255 	size_t kbytes;
256 
257 	switch (softstate->tsoft_devid) {
258 	case INTEL_BR_810:
259 	case INTEL_BR_810DC:
260 	case INTEL_BR_810E:
261 		memval = pci_config_get8(softstate->tsoft_pcihdl,
262 		    I810_CONF_SMRAM);
263 		switch (memval & I810_GMS_MASK) {
264 		case 0x80:
265 			kbytes = 512; /* 512K preallocated memory */
266 			break;
267 		case 0xc0:
268 			kbytes = 1024; /* 1024K preallocated memory */
269 			break;
270 		default:
271 			kbytes = 0; /* an unexpected case */
272 		}
273 		break;
274 	case INTEL_BR_830M:
275 	case INTEL_BR_845:
276 		memval = pci_config_get8(softstate->tsoft_pcihdl, I8XX_CONF_GC);
277 		switch (memval & I8XX_GC_MODE_MASK) {
278 		case I8XX_GC_MODE2:
279 			kbytes = 512; /* 512K preallocated memory */
280 			break;
281 		case I8XX_GC_MODE3:
282 			kbytes = 1024; /* 1M preallocated memory */
283 			break;
284 		case I8XX_GC_MODE4:
285 			kbytes = 8 * 1024; /* 8M preallocated memory */
286 			break;
287 		default:
288 			kbytes = 0; /* an unexpected case */
289 		}
290 		break;
291 	case INTEL_BR_855GM:
292 		memval = pci_config_get8(softstate->tsoft_pcihdl, I8XX_CONF_GC);
293 		switch (memval & I8XX_GC_MODE_MASK) {
294 		case I8XX_GC_MODE1:
295 			kbytes = 1024; /* 1M preallocated memory */
296 			break;
297 		case I8XX_GC_MODE2:
298 			kbytes = 4 * 1024; /* 4M preallocated memory */
299 			break;
300 		case I8XX_GC_MODE3:
301 			kbytes = 8 * 1024; /* 8M preallocated memory */
302 			break;
303 		case I8XX_GC_MODE4:
304 			kbytes = 16 * 1024; /* 16M preallocated memory */
305 			break;
306 		case I8XX_GC_MODE5:
307 			kbytes = 32 * 1024; /* 32M preallocated memory */
308 			break;
309 		default:
310 			kbytes = 0; /* an unexpected case */
311 		}
312 		break;
313 	case INTEL_BR_865:
314 	case INTEL_BR_910M:
315 		memval = pci_config_get8(softstate->tsoft_pcihdl, I8XX_CONF_GC);
316 		switch (memval & I8XX_GC_MODE_MASK) {
317 		case I8XX_GC_MODE1:
318 			kbytes = 1024; /* 1M preallocated memory */
319 			break;
320 		case I8XX_GC_MODE3:
321 			kbytes = 8 * 1024; /* 8M preallocated memory */
322 			break;
323 		/*
324 		 * There is no option for 16M in 910GM datasheet,
325 		 * but some BIOS add this option for 16M support.
326 		 */
327 		case I8XX_GC_MODE4:
328 			kbytes = 16 * 1024; /* 16M preallocated memory */
329 			break;
330 		default:
331 			kbytes = 0; /* an unexpected case */
332 		}
333 		break;
334 	case INTEL_BR_910:
335 	case INTEL_BR_945:
336 	case INTEL_BR_945GM:
337 		memval = pci_config_get8(softstate->tsoft_pcihdl, I8XX_CONF_GC);
338 		switch (memval & I8XX_GC_MODE_MASK) {
339 		case I8XX_GC_MODE1:
340 			kbytes = 1024; /* 1M preallocated memory */
341 			break;
342 		case I8XX_GC_MODE3:
343 			kbytes = 8 * 1024; /* 8M preallocated memory */
344 			break;
345 		default:
346 			kbytes = 0; /* an unexpected case */
347 		}
348 		break;
349 	default:
350 		kbytes = 0;
351 	}
352 
353 	return (kbytes);
354 }
355 
356 /*ARGSUSED*/
357 static int agptarget_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd,
358     void *arg, void **resultp)
359 {
360 	agp_target_softstate_t *st;
361 	int instance, rval = DDI_FAILURE;
362 	dev_t dev;
363 
364 	switch (cmd) {
365 	case DDI_INFO_DEVT2DEVINFO:
366 		dev = (dev_t)arg;
367 		instance = DEV2INST(dev);
368 		st = ddi_get_soft_state(agptarget_glob_soft_handle, instance);
369 		if (st != NULL) {
370 			mutex_enter(&st->tsoft_lock);
371 			*resultp = st->tsoft_dip;
372 			mutex_exit(&st->tsoft_lock);
373 			rval = DDI_SUCCESS;
374 		} else
375 			*resultp = NULL;
376 
377 		break;
378 	case DDI_INFO_DEVT2INSTANCE:
379 		dev = (dev_t)arg;
380 		instance = DEV2INST(dev);
381 		*resultp = (void *)(uintptr_t)instance;
382 		rval = DDI_SUCCESS;
383 	default:
384 		break;
385 	}
386 
387 	return (rval);
388 }
389 
390 static int
391 agp_target_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
392 {
393 	agp_target_softstate_t *softstate;
394 	int instance;
395 	int status;
396 
397 	if (cmd != DDI_ATTACH)
398 		return (DDI_FAILURE);
399 
400 	instance = ddi_get_instance(dip);
401 
402 	if (ddi_soft_state_zalloc(agptarget_glob_soft_handle, instance) !=
403 	    DDI_SUCCESS)
404 		return (DDI_FAILURE);
405 
406 	softstate = ddi_get_soft_state(agptarget_glob_soft_handle, instance);
407 	mutex_init(&softstate->tsoft_lock, NULL, MUTEX_DRIVER, NULL);
408 	softstate->tsoft_dip = dip;
409 	status = pci_config_setup(dip, &softstate->tsoft_pcihdl);
410 	if (status != DDI_SUCCESS) {
411 		ddi_soft_state_free(agptarget_glob_soft_handle, instance);
412 		return (DDI_FAILURE);
413 	}
414 
415 	softstate->tsoft_devid = pci_config_get32(softstate->tsoft_pcihdl,
416 	    PCI_CONF_VENID);
417 	softstate->tsoft_acaptr = agp_target_cap_find(softstate->tsoft_pcihdl);
418 	if (softstate->tsoft_acaptr == 0) {
419 		/* Make a correction for some Intel chipsets */
420 		if ((softstate->tsoft_devid & VENDOR_ID_MASK) ==
421 		    INTEL_VENDOR_ID)
422 			softstate->tsoft_acaptr = AGP_CAP_OFF_DEF;
423 		else
424 			return (DDI_FAILURE);
425 	}
426 
427 	status = ddi_create_minor_node(dip, AGPTARGET_NAME, S_IFCHR,
428 	    INST2NODENUM(instance), DDI_NT_AGP_TARGET, 0);
429 
430 	if (status != DDI_SUCCESS) {
431 		pci_config_teardown(&softstate->tsoft_pcihdl);
432 		ddi_soft_state_free(agptarget_glob_soft_handle, instance);
433 		return (DDI_FAILURE);
434 	}
435 
436 	return (DDI_SUCCESS);
437 }
438 
439 /*ARGSUSED*/
440 static int
441 agp_target_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
442 {
443 	int instance;
444 	agp_target_softstate_t *softstate;
445 
446 	if (cmd != DDI_DETACH)
447 		return (DDI_FAILURE);
448 
449 	instance = ddi_get_instance(dip);
450 
451 	softstate = ddi_get_soft_state(agptarget_glob_soft_handle, instance);
452 
453 	ddi_remove_minor_node(dip, AGPTARGET_NAME);
454 	pci_config_teardown(&softstate->tsoft_pcihdl);
455 	mutex_destroy(&softstate->tsoft_lock);
456 	ddi_soft_state_free(agptarget_glob_soft_handle, instance);
457 	return (DDI_SUCCESS);
458 }
459 
460 /*ARGSUSED*/
461 static int
462 agp_target_ioctl(dev_t dev, int cmd, intptr_t data, int mode,
463     cred_t *cred, int *rval)
464 {
465 	int instance = DEV2INST(dev);
466 	agp_target_softstate_t *st;
467 	static char kernel_only[] =
468 	    "amd64_gart_ioctl: is a kernel only ioctl";
469 
470 	if (!(mode & FKIOCTL)) {
471 		TARGETDB_PRINT2((CE_CONT, kernel_only));
472 		return (ENXIO);
473 	}
474 	st = GETSOFTC(instance);
475 
476 	if (st == NULL)
477 		return (ENXIO);
478 
479 	mutex_enter(&st->tsoft_lock);
480 
481 	switch (cmd) {
482 	case CHIP_DETECT:
483 	{
484 		int type;
485 		switch (st->tsoft_devid & VENDOR_ID_MASK) {
486 		case INTEL_VENDOR_ID:
487 			type = CHIP_IS_INTEL;
488 			break;
489 		case AMD_VENDOR_ID:
490 			type = CHIP_IS_AMD;
491 			break;
492 		default:
493 			type = 0;
494 		}
495 		if (ddi_copyout(&type, (void *)data, sizeof (int), mode)) {
496 			mutex_exit(&st->tsoft_lock);
497 			return (EFAULT);
498 		}
499 
500 		break;
501 	}
502 	case I8XX_GET_PREALLOC_SIZE:
503 	{
504 		size_t prealloc_size;
505 
506 		if ((st->tsoft_devid & VENDOR_ID_MASK) !=
507 		    INTEL_VENDOR_ID) {
508 			mutex_exit(&st->tsoft_lock);
509 			return (EINVAL);
510 		}
511 
512 		prealloc_size = i8xx_biosmem_detect(st);
513 		if (ddi_copyout(&prealloc_size, (void *)data,
514 		    sizeof (size_t), mode)) {
515 			mutex_exit(&st->tsoft_lock);
516 			return (EFAULT);
517 		}
518 
519 		break;
520 	}
521 	case AGP_TARGET_GETINFO:
522 	{
523 		i_agp_info_t info;
524 		uint32_t value;
525 		off_t cap;
526 
527 		ASSERT(st->tsoft_acaptr);
528 
529 		cap = st->tsoft_acaptr;
530 		value = pci_config_get32(st->tsoft_pcihdl, cap);
531 		info.iagp_ver.agpv_major = (uint16_t)((value >> 20) & 0xf);
532 		info.iagp_ver.agpv_minor = (uint16_t)((value >> 16) & 0xf);
533 		info.iagp_devid = st->tsoft_devid;
534 		info.iagp_mode = pci_config_get32(st->tsoft_pcihdl,
535 		    cap + AGP_CONF_STATUS);
536 		info.iagp_aperbase = agp_target_get_apbase(st);
537 		info.iagp_apersize = agp_target_get_apsize(st);
538 
539 		if (ddi_copyout(&info, (void *)data,
540 		    sizeof (i_agp_info_t), mode)) {
541 			mutex_exit(&st->tsoft_lock);
542 			return (EFAULT);
543 		}
544 		break;
545 
546 	}
547 	/*
548 	 * This ioctl is only for Intel AGP chipsets.
549 	 * It is not necessary for the AMD8151 AGP bridge, because
550 	 * this register in the AMD8151 does not control any hardware.
551 	 * It is only provided for compatibility with an Intel AGP bridge.
552 	 * Please refer to the <<AMD8151 data sheet>> page 24,
553 	 * AGP device GART pointer.
554 	 */
555 	case AGP_TARGET_SET_GATTADDR:
556 	{
557 		uint32_t gartaddr;
558 
559 		if (ddi_copyin((void *)data, &gartaddr,
560 		    sizeof (uint32_t), mode)) {
561 			mutex_exit(&st->tsoft_lock);
562 			return (EFAULT);
563 		}
564 
565 		agp_target_set_gartaddr(st, gartaddr);
566 		break;
567 	}
568 	case AGP_TARGET_SETCMD:
569 	{
570 		uint32_t command;
571 
572 		if (ddi_copyin((void *)data, &command,
573 		    sizeof (uint32_t), mode)) {
574 			mutex_exit(&st->tsoft_lock);
575 			return (EFAULT);
576 		}
577 
578 		ASSERT(st->tsoft_acaptr);
579 
580 		pci_config_put32(st->tsoft_pcihdl,
581 		    st->tsoft_acaptr + AGP_CONF_COMMAND,
582 		    command);
583 		break;
584 
585 	}
586 	case AGP_TARGET_FLUSH_GTLB:
587 	{
588 		uint16_t value;
589 
590 		ASSERT(st->tsoft_acaptr);
591 
592 		value = pci_config_get16(st->tsoft_pcihdl,
593 		    st->tsoft_acaptr + AGP_CONF_CONTROL);
594 		value &= ~AGPCTRL_GTLBEN;
595 		pci_config_put16(st->tsoft_pcihdl,
596 		    st->tsoft_acaptr + AGP_CONF_CONTROL, value);
597 		value |= AGPCTRL_GTLBEN;
598 		pci_config_put16(st->tsoft_pcihdl,
599 		    st->tsoft_acaptr + AGP_CONF_CONTROL, value);
600 
601 		break;
602 	}
603 	case AGP_TARGET_CONFIGURE:
604 	{
605 		uint8_t value;
606 
607 		ASSERT(st->tsoft_acaptr);
608 
609 		value = pci_config_get8(st->tsoft_pcihdl,
610 		    st->tsoft_acaptr + AGP_CONF_MISC);
611 		value |= AGP_MISC_APEN;
612 		pci_config_put8(st->tsoft_pcihdl,
613 		    st->tsoft_acaptr + AGP_CONF_MISC, value);
614 		break;
615 
616 	}
617 	case AGP_TARGET_UNCONFIG:
618 	{
619 		uint32_t value1;
620 		uint8_t value2;
621 
622 		ASSERT(st->tsoft_acaptr);
623 
624 		pci_config_put16(st->tsoft_pcihdl,
625 		    st->tsoft_acaptr + AGP_CONF_CONTROL, 0x0);
626 
627 		value2 = pci_config_get8(st->tsoft_pcihdl,
628 		    st->tsoft_acaptr + AGP_CONF_MISC);
629 		value2 &= ~AGP_MISC_APEN;
630 		pci_config_put8(st->tsoft_pcihdl,
631 		    st->tsoft_acaptr + AGP_CONF_MISC, value2);
632 
633 		value1 = pci_config_get32(st->tsoft_pcihdl,
634 		    st->tsoft_acaptr + AGP_CONF_COMMAND);
635 		value1 &= ~AGPCMD_AGPEN;
636 		pci_config_put32(st->tsoft_pcihdl,
637 		    st->tsoft_acaptr + AGP_CONF_COMMAND,
638 		    value1);
639 
640 		pci_config_put32(st->tsoft_pcihdl,
641 		    st->tsoft_acaptr + AGP_CONF_ATTBASE, 0x0);
642 
643 		break;
644 	}
645 
646 	default:
647 		mutex_exit(&st->tsoft_lock);
648 		return (ENXIO);
649 	} /* end switch */
650 
651 	mutex_exit(&st->tsoft_lock);
652 
653 	return (0);
654 }
655 
656 /*ARGSUSED*/
657 static int
658 agp_target_open(dev_t *devp, int flag, int otyp, cred_t *cred)
659 {
660 	int instance = DEV2INST(*devp);
661 	agp_target_softstate_t *st;
662 
663 	if (!(flag & FKLYR))
664 		return (ENXIO);
665 
666 	st = GETSOFTC(instance);
667 
668 	if (st == NULL)
669 		return (ENXIO);
670 
671 	return (0);
672 }
673 
674 /*ARGSUSED*/
675 static int
676 agp_target_close(dev_t dev, int flag, int otyp, cred_t *cred)
677 {
678 	int instance = DEV2INST(dev);
679 	agp_target_softstate_t *st;
680 
681 	st = GETSOFTC(instance);
682 
683 	if (st == NULL)
684 		return (ENXIO);
685 
686 	return (0);
687 }
688 
689 static  struct  cb_ops  agp_target_cb_ops = {
690 	agp_target_open,		/* cb_open */
691 	agp_target_close,		/* cb_close */
692 	nodev,				/* cb_strategy */
693 	nodev,				/* cb_print */
694 	nodev,				/* cb_dump */
695 	nodev,				/* cb_read() */
696 	nodev,				/* cb_write() */
697 	agp_target_ioctl,		/* cb_ioctl */
698 	nodev,				/* cb_devmap */
699 	nodev,				/* cb_mmap */
700 	nodev,				/* cb_segmap */
701 	nochpoll,			/* cb_chpoll */
702 	ddi_prop_op,			/* cb_prop_op */
703 	0,				/* cb_stream */
704 	D_NEW | D_MP, 			/* cb_flag */
705 	CB_REV,				/* cb_ops version? */
706 	nodev,				/* cb_aread() */
707 	nodev,				/* cb_awrite() */
708 };
709 
710 /* device operations */
711 static struct dev_ops agp_target_ops = {
712 	DEVO_REV,		/* devo_rev */
713 	0,			/* devo_refcnt */
714 	agptarget_getinfo, 	/* devo_getinfo */
715 	nulldev,		/* devo_identify */
716 	nulldev,		/* devo_probe */
717 	agp_target_attach,	/* devo_attach */
718 	agp_target_detach,	/* devo_detach */
719 	nodev,			/* devo_reset */
720 	&agp_target_cb_ops,	/* devo_cb_ops */
721 	0,			/* devo_bus_ops */
722 	0,			/* devo_power */
723 };
724 
725 static  struct modldrv modldrv = {
726 	&mod_driverops,
727 	"AGP target driver v%I%",
728 	&agp_target_ops,
729 };
730 
731 static  struct modlinkage modlinkage = {
732 	MODREV_1,		/* MODREV_1 is indicated by manual */
733 	{&modldrv, NULL, NULL, NULL}
734 };
735 
736 int
737 _init(void)
738 {
739 	int ret;
740 
741 	ret = ddi_soft_state_init(&agptarget_glob_soft_handle,
742 	    sizeof (agp_target_softstate_t), 1);
743 
744 	if (ret)
745 		goto err1;
746 
747 	if ((ret = mod_install(&modlinkage)) != 0) {
748 		goto err2;
749 	}
750 
751 	return (DDI_SUCCESS);
752 err2:
753 	ddi_soft_state_fini(&agptarget_glob_soft_handle);
754 err1:
755 	return (ret);
756 }
757 
758 int
759 _info(struct  modinfo *modinfop)
760 {
761 	return (mod_info(&modlinkage, modinfop));
762 }
763 
764 int
765 _fini(void)
766 {
767 	int	ret;
768 
769 	if ((ret = mod_remove(&modlinkage)) == 0) {
770 		ddi_soft_state_fini(&agptarget_glob_soft_handle);
771 	}
772 	return (ret);
773 }
774