xref: /titanic_41/usr/src/uts/intel/io/agpgart/agptarget.c (revision 92d2c9e800f6d16b2980e28664926058477ef112)
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 (c) 2009, Intel Corporation.
24  * All Rights Reserved.
25  */
26 
27 /*
28  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
29  * Use is subject to license terms.
30  */
31 
32 
33 #include <sys/systm.h>
34 #include <sys/conf.h>
35 #include <sys/modctl.h>
36 #include <sys/file.h>
37 #include <sys/stat.h>
38 #include <sys/ddi.h>
39 #include <sys/sunddi.h>
40 #include <sys/sunndi.h>
41 #include <sys/modctl.h>
42 #include <sys/sunldi.h>
43 #include <sys/pci.h>
44 #include <sys/agpgart.h>
45 #include <sys/agp/agpdefs.h>
46 #include <sys/agp/agptarget_io.h>
47 
48 int agptarget_debug_var = 0;
49 #define	TARGETDB_PRINT2(fmt)	if (agptarget_debug_var >= 1) cmn_err fmt
50 #define	INST2NODENUM(inst)	(inst)
51 #define	DEV2INST(dev)		(getminor(dev))
52 
53 #define	I915_IFPADDR	0x60
54 #define	I965_IFPADDR	0x70
55 
56 #define	HIADDR(n)	((uint32_t)(((uint64_t)(n) & \
57 			0xFFFFFFFF00000000ULL) >> 32))
58 #define	LOADDR(n)	((uint32_t)((uint64_t)(n) & 0x00000000FFFFFFFF))
59 
60 typedef struct agp_target_softstate {
61 	dev_info_t		*tsoft_dip;
62 	ddi_acc_handle_t	tsoft_pcihdl;
63 	uint32_t		tsoft_devid;
64 	/* The offset of the ACAPID register */
65 	off_t			tsoft_acaptr;
66 	kmutex_t		tsoft_lock;
67 	int			tsoft_gms_off; /* GMS offset in config */
68 	uint32_t		tsoft_gms;
69 }agp_target_softstate_t;
70 
71 /*
72  * To get the pre-allocated graphics mem size using Graphics Mode Select
73  * (GMS) value.
74  */
75 typedef struct gms_mode {
76 	uint32_t	gm_devid;	/* bridge vendor + device id */
77 	off_t		gm_regoff;	/* mode selection register offset */
78 	uint32_t	gm_mask;	/* GMS mask */
79 	uint32_t	gm_num;		/* number of modes in gm_vec */
80 	int 		*gm_vec;	/* modes array */
81 } gms_mode_t;
82 
83 static void *agptarget_glob_soft_handle;
84 
85 #define	GETSOFTC(instance)	((agp_target_softstate_t *)	\
86     ddi_get_soft_state(agptarget_glob_soft_handle, instance));
87 
88 /*
89  * The AMD8151 bridge is the only supported 64 bit hardware
90  */
91 static int
is_64bit_aper(agp_target_softstate_t * softstate)92 is_64bit_aper(agp_target_softstate_t *softstate)
93 {
94 	return (softstate->tsoft_devid == AMD_BR_8151);
95 }
96 
97 /*
98  * Check if it is an intel bridge
99  */
100 static int
is_intel_br(agp_target_softstate_t * softstate)101 is_intel_br(agp_target_softstate_t *softstate)
102 {
103 	return ((softstate->tsoft_devid & VENDOR_ID_MASK) ==
104 	    INTEL_VENDOR_ID);
105 }
106 
107 /*
108  * agp_target_cap_find()
109  *
110  * Description:
111  * 	This function searches the linked capability list to find the offset
112  * 	of the AGP capability register. When it was not found, return 0.
113  * 	This works for standard AGP chipsets, but not for some Intel chipsets,
114  * 	like the I830M/I830MP/I852PM/I852GME/I855GME. It will return 0 for
115  * 	these chipsets even if AGP is supported. So the offset of acapid
116  * 	should be set manually in thoses cases.
117  *
118  * Arguments:
119  * 	pci_handle		ddi acc handle of pci config
120  *
121  * Returns:
122  * 	0			No capability pointer register found
123  * 	nexcap			The AGP capability pointer register offset
124  */
125 static off_t
agp_target_cap_find(ddi_acc_handle_t pci_handle)126 agp_target_cap_find(ddi_acc_handle_t pci_handle)
127 {
128 	off_t		nextcap = 0;
129 	uint32_t	ncapid = 0;
130 	uint8_t		value = 0;
131 
132 	/* Check if this device supports the capability pointer */
133 	value = (uint8_t)(pci_config_get16(pci_handle, PCI_CONF_STAT)
134 	    & PCI_CONF_CAP_MASK);
135 
136 	if (!value)
137 		return (0);
138 	/* Get the offset of the first capability pointer from CAPPTR */
139 	nextcap = (off_t)(pci_config_get8(pci_handle, AGP_CONF_CAPPTR));
140 
141 	/* Check the AGP capability from the first capability pointer */
142 	while (nextcap) {
143 		ncapid = pci_config_get32(pci_handle, nextcap);
144 		/*
145 		 * AGP3.0 rev1.0 127  the capid was assigned by the PCI SIG,
146 		 * 845 data sheet page 69
147 		 */
148 		if ((ncapid & PCI_CONF_CAPID_MASK) ==
149 		    AGP_CAP_ID) /* The AGP cap was found */
150 			break;
151 
152 		nextcap = (off_t)((ncapid & PCI_CONF_NCAPID_MASK) >> 8);
153 	}
154 
155 	return (nextcap);
156 
157 }
158 
159 /*
160  * agp_target_get_aperbase()
161  *
162  * Description:
163  * 	This function gets the AGP aperture base address from the AGP target
164  *	register, the AGP aperture base register was programmed by the BIOS.
165  *
166  * Arguments:
167  * 	softstate		driver soft state pointer
168  *
169  * Returns:
170  * 	aper_base 		AGP aperture base address
171  *
172  * Notes:
173  * 	If a 64bit bridge device is available, the AGP aperture base address
174  * 	can be 64 bit.
175  */
176 static uint64_t
agp_target_get_apbase(agp_target_softstate_t * softstate)177 agp_target_get_apbase(agp_target_softstate_t *softstate)
178 {
179 	uint64_t aper_base;
180 
181 	if (is_intel_br(softstate)) {
182 		aper_base = pci_config_get32(softstate->tsoft_pcihdl,
183 		    AGP_CONF_APERBASE) & AGP_32_APERBASE_MASK;
184 	} else if (is_64bit_aper(softstate)) {
185 		aper_base = pci_config_get64(softstate->tsoft_pcihdl,
186 		    AGP_CONF_APERBASE);
187 		/* 32-bit or 64-bit aperbase base pointer */
188 		if ((aper_base & AGP_APER_TYPE_MASK) == 0)
189 			aper_base &= AGP_32_APERBASE_MASK;
190 		else
191 			aper_base &= AGP_64_APERBASE_MASK;
192 	}
193 
194 	return (aper_base);
195 }
196 
197 /*
198  * agp_target_get_apsize()
199  *
200  * Description:
201  * 	This function gets the AGP aperture size by reading the AGP aperture
202  * 	size register.
203  * Arguments:
204  * 	softstate		driver soft state pointer
205  *
206  * Return:
207  * 	size		The AGP aperture size in megabytes
208  * 	0		an unexpected error
209  */
210 static size_t
agp_target_get_apsize(agp_target_softstate_t * softstate)211 agp_target_get_apsize(agp_target_softstate_t *softstate)
212 {
213 	off_t cap;
214 	uint16_t value;
215 	size_t size, regsize;
216 
217 	ASSERT(softstate->tsoft_acaptr);
218 	cap = softstate->tsoft_acaptr;
219 
220 	if (is_intel_br(softstate)) {
221 		/* extend this value to 16 bit for later tests */
222 		value = (uint16_t)pci_config_get8(softstate->tsoft_pcihdl,
223 		    cap + AGP_CONF_APERSIZE) | AGP_APER_SIZE_MASK;
224 	} else if (is_64bit_aper(softstate)) {
225 		value = pci_config_get16(softstate->tsoft_pcihdl,
226 		    cap + AGP_CONF_APERSIZE);
227 	}
228 
229 	if (value & AGP_APER_128M_MASK) {
230 		switch (value & AGP_APER_128M_MASK) {
231 			case AGP_APER_4M:
232 				size = 4; /* 4M */
233 				break;
234 			case AGP_APER_8M:
235 				size = 8; /* 8M */
236 				break;
237 			case AGP_APER_16M:
238 				size = 16; /* 16M */
239 				break;
240 			case AGP_APER_32M:
241 				size = 32; /* 32M */
242 				break;
243 			case AGP_APER_64M:
244 				size = 64; /* 64M */
245 				break;
246 			case AGP_APER_128M:
247 				size = 128; /* 128M */
248 				break;
249 			default:
250 				size = 0; /* not true */
251 		}
252 	} else {
253 		switch (value & AGP_APER_4G_MASK) {
254 			case AGP_APER_256M:
255 				size = 256; /* 256 M */
256 				break;
257 			case AGP_APER_512M:
258 				size = 512; /* 512 M */
259 				break;
260 			case AGP_APER_1024M:
261 				size = 1024; /* 1024 M */
262 				break;
263 			case AGP_APER_2048M:
264 				size = 2048; /* 2048 M */
265 				break;
266 			case AGP_APER_4G:
267 				size = 4096; /* 4096 M */
268 				break;
269 			default:
270 				size = 0; /* not true */
271 		}
272 	}
273 	/*
274 	 * In some cases, there is no APSIZE register, so the size value
275 	 * of 256M could be wrong. Check the value by reading the size of
276 	 * the first register which was set in the PCI configuration space.
277 	 */
278 	if (size == 256) {
279 		if (ddi_dev_regsize(softstate->tsoft_dip,
280 		    AGP_TARGET_BAR1, (off_t *)&regsize) == DDI_FAILURE)
281 			return (0);
282 
283 		if (MB2BYTES(size) != regsize) {
284 			TARGETDB_PRINT2((CE_WARN,
285 			    "APSIZE 256M doesn't match regsize %lx",
286 			    regsize));
287 			TARGETDB_PRINT2((CE_WARN, "Use regsize instead"));
288 			size = BYTES2MB(regsize);
289 		}
290 	}
291 
292 	return (size);
293 }
294 
295 static void
agp_target_set_gartaddr(agp_target_softstate_t * softstate,uint32_t gartaddr)296 agp_target_set_gartaddr(agp_target_softstate_t *softstate, uint32_t gartaddr)
297 {
298 	ASSERT(softstate->tsoft_acaptr);
299 
300 	/* Disable the GTLB for Intel chipsets */
301 	pci_config_put16(softstate->tsoft_pcihdl,
302 	    softstate->tsoft_acaptr + AGP_CONF_CONTROL, 0x0000);
303 
304 	pci_config_put32(softstate->tsoft_pcihdl,
305 	    softstate->tsoft_acaptr + AGP_CONF_ATTBASE,
306 	    gartaddr & AGP_ATTBASE_MASK);
307 }
308 
309 /*
310  * Pre-allocated graphics memory for every type of Intel north bridge, mem size
311  * are specified in kbytes.
312  */
313 #define	GMS_MB(n) 	((n) * 1024)
314 #define	GMS_SHIFT 	4
315 #define	GMS_SIZE(a)	(sizeof (a) / sizeof (int))
316 
317 /*
318  * Since value zero always means "No memory pre-allocated", value of (GMS - 1)
319  * is used to index these arrays, i.e. gms_xxx[1] contains the mem size (in kb)
320  * that GMS value 0x1 corresponding to.
321  *
322  * Assuming all "reserved" GMS value as zero bytes of pre-allocated graphics
323  * memory, unless some special BIOS settings exist.
324  */
325 static int gms_810[12] = {0, 0, 0, 0, 0, 0, 0, 512, 0, 0, 0, GMS_MB(1)};
326 static int gms_830_845[4] = {0, 512, GMS_MB(1), GMS_MB(8)};
327 static int gms_855GM[5] = {GMS_MB(1), GMS_MB(4), GMS_MB(8), GMS_MB(16),
328 	GMS_MB(32)};
329 /* There is no modes for 16M in datasheet, but some BIOS add it. */
330 static int gms_865_915GM[4] = {GMS_MB(1), 0, GMS_MB(8), GMS_MB(16)};
331 static int gms_915_945_965[3] = {GMS_MB(1), 0, GMS_MB(8)};
332 static int gms_965GM[7] = {GMS_MB(1), GMS_MB(4), GMS_MB(8), GMS_MB(16),
333 	GMS_MB(32), GMS_MB(48), GMS_MB(64)};
334 static int gms_X33[9] = {GMS_MB(1), GMS_MB(4), GMS_MB(8), GMS_MB(16),
335 	GMS_MB(32), GMS_MB(48), GMS_MB(64), GMS_MB(128), GMS_MB(256)};
336 static int gms_G4X[13] = {0, 0, 0, 0,
337 	GMS_MB(32), GMS_MB(48), GMS_MB(64), GMS_MB(128), GMS_MB(256),
338 	GMS_MB(96), GMS_MB(160), GMS_MB(224), GMS_MB(352)};
339 
340 static gms_mode_t gms_modes[] = {
341 	{INTEL_BR_810, I810_CONF_SMRAM, I810_GMS_MASK,
342 		GMS_SIZE(gms_810), gms_810},
343 	{INTEL_BR_810DC, I810_CONF_SMRAM, I810_GMS_MASK,
344 		GMS_SIZE(gms_810), gms_810},
345 	{INTEL_BR_810E, I810_CONF_SMRAM, I810_GMS_MASK,
346 		GMS_SIZE(gms_810), gms_810},
347 	{INTEL_BR_830M, I8XX_CONF_GC, I8XX_GC_MODE_MASK,
348 		GMS_SIZE(gms_830_845), gms_830_845},
349 	{INTEL_BR_845, I8XX_CONF_GC, I8XX_GC_MODE_MASK,
350 		GMS_SIZE(gms_830_845), gms_830_845},
351 	{INTEL_BR_855GM, I8XX_CONF_GC, I8XX_GC_MODE_MASK,
352 		GMS_SIZE(gms_855GM), gms_855GM},
353 	{INTEL_BR_865, I8XX_CONF_GC, I8XX_GC_MODE_MASK,
354 		GMS_SIZE(gms_865_915GM), gms_865_915GM},
355 	{INTEL_BR_915GM, I8XX_CONF_GC, I8XX_GC_MODE_MASK,
356 		GMS_SIZE(gms_865_915GM), gms_865_915GM},
357 	{INTEL_BR_915, I8XX_CONF_GC, I8XX_GC_MODE_MASK,
358 		GMS_SIZE(gms_915_945_965), gms_915_945_965},
359 	{INTEL_BR_945, I8XX_CONF_GC, I8XX_GC_MODE_MASK,
360 		GMS_SIZE(gms_915_945_965), gms_915_945_965},
361 	{INTEL_BR_945GM, I8XX_CONF_GC, I8XX_GC_MODE_MASK,
362 		GMS_SIZE(gms_915_945_965), gms_915_945_965},
363 	{INTEL_BR_945GME, I8XX_CONF_GC, I8XX_GC_MODE_MASK,
364 		GMS_SIZE(gms_915_945_965), gms_915_945_965},
365 	{INTEL_BR_946GZ, I8XX_CONF_GC, I8XX_GC_MODE_MASK,
366 		GMS_SIZE(gms_915_945_965), gms_915_945_965},
367 	{INTEL_BR_965G1, I8XX_CONF_GC, I8XX_GC_MODE_MASK,
368 		GMS_SIZE(gms_915_945_965), gms_915_945_965},
369 	{INTEL_BR_965G2, I8XX_CONF_GC, I8XX_GC_MODE_MASK,
370 		GMS_SIZE(gms_915_945_965), gms_915_945_965},
371 	{INTEL_BR_965Q, I8XX_CONF_GC, I8XX_GC_MODE_MASK,
372 		GMS_SIZE(gms_915_945_965), gms_915_945_965},
373 	{INTEL_BR_965GM, I8XX_CONF_GC, I8XX_GC_MODE_MASK,
374 		GMS_SIZE(gms_965GM), gms_965GM},
375 	{INTEL_BR_965GME, I8XX_CONF_GC, I8XX_GC_MODE_MASK,
376 		GMS_SIZE(gms_965GM), gms_965GM},
377 	{INTEL_BR_Q35, I8XX_CONF_GC, IX33_GC_MODE_MASK,
378 		GMS_SIZE(gms_X33), gms_X33},
379 	{INTEL_BR_G33, I8XX_CONF_GC, IX33_GC_MODE_MASK,
380 		GMS_SIZE(gms_X33), gms_X33},
381 	{INTEL_BR_Q33, I8XX_CONF_GC, IX33_GC_MODE_MASK,
382 		GMS_SIZE(gms_X33), gms_X33},
383 	{INTEL_BR_GM45, I8XX_CONF_GC, I8XX_GC_MODE_MASK,
384 		GMS_SIZE(gms_965GM), gms_965GM},
385 	{INTEL_BR_EL, I8XX_CONF_GC, I8XX_GC_MODE_MASK,
386 		GMS_SIZE(gms_G4X), gms_G4X},
387 	{INTEL_BR_Q45, I8XX_CONF_GC, I8XX_GC_MODE_MASK,
388 		GMS_SIZE(gms_G4X), gms_G4X},
389 	{INTEL_BR_G45, I8XX_CONF_GC, I8XX_GC_MODE_MASK,
390 		GMS_SIZE(gms_G4X), gms_G4X},
391 	{INTEL_BR_G41, I8XX_CONF_GC, I8XX_GC_MODE_MASK,
392 		GMS_SIZE(gms_G4X), gms_G4X},
393 	{INTEL_BR_IGDNG_D, I8XX_CONF_GC, I8XX_GC_MODE_MASK,
394 		GMS_SIZE(gms_G4X), gms_G4X},
395 	{INTEL_BR_IGDNG_M, I8XX_CONF_GC, I8XX_GC_MODE_MASK,
396 		GMS_SIZE(gms_G4X), gms_G4X},
397 	{INTEL_BR_IGDNG_MA, I8XX_CONF_GC, I8XX_GC_MODE_MASK,
398 		GMS_SIZE(gms_G4X), gms_G4X},
399 	{INTEL_BR_IGDNG_MC2, I8XX_CONF_GC, I8XX_GC_MODE_MASK,
400 		GMS_SIZE(gms_G4X), gms_G4X},
401 	{INTEL_BR_B43, I8XX_CONF_GC, I8XX_GC_MODE_MASK,
402 		GMS_SIZE(gms_G4X), gms_G4X}
403 };
404 static int
get_chip_gms(uint32_t devid)405 get_chip_gms(uint32_t devid)
406 {
407 	int num_modes;
408 	int i;
409 
410 	num_modes = (sizeof (gms_modes) / sizeof (gms_mode_t));
411 
412 	for (i = 0; i < num_modes; i++) {
413 		if (gms_modes[i].gm_devid == devid)
414 			break;
415 	}
416 
417 	return ((i == num_modes) ? -1 : i);
418 }
419 
420 /* Returns the size (kbytes) of pre-allocated graphics memory */
421 static size_t
i8xx_biosmem_detect(agp_target_softstate_t * softstate)422 i8xx_biosmem_detect(agp_target_softstate_t *softstate)
423 {
424 	uint8_t memval;
425 	size_t kbytes;
426 	int	gms_off;
427 
428 	kbytes = 0;
429 	gms_off = softstate->tsoft_gms_off;
430 
431 	/* fetch the GMS value from DRAM controller */
432 	memval = pci_config_get8(softstate->tsoft_pcihdl,
433 	    gms_modes[gms_off].gm_regoff);
434 	TARGETDB_PRINT2((CE_NOTE, "i8xx_biosmem_detect: memval = %x", memval));
435 	memval = (memval & gms_modes[gms_off].gm_mask) >> GMS_SHIFT;
436 	/* assuming zero byte for 0 or "reserved" GMS values */
437 	if (memval == 0 || memval > gms_modes[gms_off].gm_num) {
438 		TARGETDB_PRINT2((CE_WARN, "i8xx_biosmem_detect: "
439 		    "devid = %x, GMS = %x. assuming zero byte of "
440 		    "pre-allocated memory",
441 		    gms_modes[gms_off].gm_devid, memval));
442 		goto done;
443 	}
444 	memval--;	/* use (GMS_value - 1) as index */
445 	kbytes = (gms_modes[gms_off].gm_vec)[memval];
446 
447 done:
448 	TARGETDB_PRINT2((CE_NOTE,
449 	    "i8xx_biosmem_detect: %ldKB BIOS pre-allocated memory detected",
450 	    kbytes));
451 	return (kbytes);
452 }
453 
454 /*ARGSUSED*/
agptarget_getinfo(dev_info_t * dip,ddi_info_cmd_t cmd,void * arg,void ** resultp)455 static int agptarget_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd,
456     void *arg, void **resultp)
457 {
458 	agp_target_softstate_t *st;
459 	int instance, rval = DDI_FAILURE;
460 	dev_t dev;
461 
462 	switch (cmd) {
463 	case DDI_INFO_DEVT2DEVINFO:
464 		dev = (dev_t)arg;
465 		instance = DEV2INST(dev);
466 		st = ddi_get_soft_state(agptarget_glob_soft_handle, instance);
467 		if (st != NULL) {
468 			mutex_enter(&st->tsoft_lock);
469 			*resultp = st->tsoft_dip;
470 			mutex_exit(&st->tsoft_lock);
471 			rval = DDI_SUCCESS;
472 		} else
473 			*resultp = NULL;
474 
475 		break;
476 	case DDI_INFO_DEVT2INSTANCE:
477 		dev = (dev_t)arg;
478 		instance = DEV2INST(dev);
479 		*resultp = (void *)(uintptr_t)instance;
480 		rval = DDI_SUCCESS;
481 	default:
482 		break;
483 	}
484 
485 	return (rval);
486 }
487 
488 static int
intel_br_resume(agp_target_softstate_t * softstate)489 intel_br_resume(agp_target_softstate_t *softstate)
490 {
491 	int gms_off;
492 
493 	gms_off = softstate->tsoft_gms_off;
494 
495 	/*
496 	 * We recover the gmch graphics control register here
497 	 */
498 	pci_config_put16(softstate->tsoft_pcihdl,
499 	    gms_modes[gms_off].gm_regoff, softstate->tsoft_gms);
500 
501 	return (DDI_SUCCESS);
502 }
503 static int
intel_br_suspend(agp_target_softstate_t * softstate)504 intel_br_suspend(agp_target_softstate_t *softstate)
505 {
506 	int gms_off;
507 
508 	gms_off = softstate->tsoft_gms_off;
509 	softstate->tsoft_gms = pci_config_get16(softstate->tsoft_pcihdl,
510 	    gms_modes[gms_off].gm_regoff);
511 
512 	return (DDI_SUCCESS);
513 }
514 
515 static int
agp_target_attach(dev_info_t * dip,ddi_attach_cmd_t cmd)516 agp_target_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
517 {
518 	agp_target_softstate_t *softstate;
519 	int instance;
520 	int status;
521 
522 	instance = ddi_get_instance(dip);
523 
524 	switch (cmd) {
525 	case DDI_ATTACH:
526 		break;
527 	case DDI_RESUME:
528 		softstate =
529 		    ddi_get_soft_state(agptarget_glob_soft_handle, instance);
530 		return (intel_br_resume(softstate));
531 	default:
532 		TARGETDB_PRINT2((CE_WARN, "agp_target_attach:"
533 		    "only attach and resume ops are supported"));
534 		return (DDI_FAILURE);
535 	}
536 
537 	if (ddi_soft_state_zalloc(agptarget_glob_soft_handle,
538 	    instance) != DDI_SUCCESS) {
539 		TARGETDB_PRINT2((CE_WARN, "agp_target_attach:"
540 		    "soft state zalloc failed"));
541 		return (DDI_FAILURE);
542 	}
543 
544 	softstate = ddi_get_soft_state(agptarget_glob_soft_handle, instance);
545 	mutex_init(&softstate->tsoft_lock, NULL, MUTEX_DRIVER, NULL);
546 	softstate->tsoft_dip = dip;
547 	status = pci_config_setup(dip, &softstate->tsoft_pcihdl);
548 	if (status != DDI_SUCCESS) {
549 		TARGETDB_PRINT2((CE_WARN, "agp_target_attach:"
550 		    "pci config setup failed"));
551 		ddi_soft_state_free(agptarget_glob_soft_handle,
552 		    instance);
553 		return (DDI_FAILURE);
554 	}
555 
556 	softstate->tsoft_devid = pci_config_get32(softstate->tsoft_pcihdl,
557 	    PCI_CONF_VENID);
558 	softstate->tsoft_gms_off = get_chip_gms(softstate->tsoft_devid);
559 	if (softstate->tsoft_gms_off < 0) {
560 		TARGETDB_PRINT2((CE_WARN, "agp_target_attach:"
561 		    "read gms offset failed"));
562 		pci_config_teardown(&softstate->tsoft_pcihdl);
563 		ddi_soft_state_free(agptarget_glob_soft_handle,
564 		    instance);
565 		return (DDI_FAILURE);
566 	}
567 	softstate->tsoft_acaptr = agp_target_cap_find(softstate->tsoft_pcihdl);
568 	if (softstate->tsoft_acaptr == 0) {
569 		/* Make a correction for some Intel chipsets */
570 		if (is_intel_br(softstate))
571 			softstate->tsoft_acaptr = AGP_CAP_OFF_DEF;
572 		else {
573 			TARGETDB_PRINT2((CE_WARN, "agp_target_attach:"
574 			    "Not a supposed corretion"));
575 			pci_config_teardown(&softstate->tsoft_pcihdl);
576 			ddi_soft_state_free(agptarget_glob_soft_handle,
577 			    instance);
578 			return (DDI_FAILURE);
579 		}
580 	}
581 
582 	status = ddi_create_minor_node(dip, AGPTARGET_NAME, S_IFCHR,
583 	    INST2NODENUM(instance), DDI_NT_AGP_TARGET, 0);
584 
585 	if (status != DDI_SUCCESS) {
586 		TARGETDB_PRINT2((CE_WARN, "agp_target_attach:"
587 		    "Create minor node failed"));
588 		pci_config_teardown(&softstate->tsoft_pcihdl);
589 		ddi_soft_state_free(agptarget_glob_soft_handle, instance);
590 		return (DDI_FAILURE);
591 	}
592 
593 	return (DDI_SUCCESS);
594 }
595 
596 /*ARGSUSED*/
597 static int
agp_target_detach(dev_info_t * dip,ddi_detach_cmd_t cmd)598 agp_target_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
599 {
600 	int instance;
601 	agp_target_softstate_t *softstate;
602 
603 	instance = ddi_get_instance(dip);
604 	softstate = ddi_get_soft_state(agptarget_glob_soft_handle, instance);
605 
606 	if (cmd == DDI_SUSPEND) {
607 		/* get GMS modes list entry */
608 		return (intel_br_suspend(softstate));
609 	}
610 
611 	if (cmd != DDI_DETACH) {
612 		TARGETDB_PRINT2((CE_WARN, "agp_target_detach:"
613 		    "only detach and suspend ops are supported"));
614 		return (DDI_FAILURE);
615 	}
616 
617 	ddi_remove_minor_node(dip, AGPTARGET_NAME);
618 	pci_config_teardown(&softstate->tsoft_pcihdl);
619 	mutex_destroy(&softstate->tsoft_lock);
620 	ddi_soft_state_free(agptarget_glob_soft_handle, instance);
621 	return (DDI_SUCCESS);
622 }
623 
624 /*ARGSUSED*/
625 static int
agp_target_ioctl(dev_t dev,int cmd,intptr_t data,int mode,cred_t * cred,int * rval)626 agp_target_ioctl(dev_t dev, int cmd, intptr_t data, int mode,
627     cred_t *cred, int *rval)
628 {
629 	int instance = DEV2INST(dev);
630 	agp_target_softstate_t *st;
631 	static char kernel_only[] =
632 	    "amd64_gart_ioctl: is a kernel only ioctl";
633 
634 	if (!(mode & FKIOCTL)) {
635 		TARGETDB_PRINT2((CE_CONT, kernel_only));
636 		return (ENXIO);
637 	}
638 	st = GETSOFTC(instance);
639 
640 	if (st == NULL)
641 		return (ENXIO);
642 
643 	mutex_enter(&st->tsoft_lock);
644 
645 	switch (cmd) {
646 	case CHIP_DETECT:
647 	{
648 		int type = 0;
649 
650 		if (is_intel_br(st))
651 			type = CHIP_IS_INTEL;
652 		else if (is_64bit_aper(st))
653 			type = CHIP_IS_AMD;
654 		else {
655 			type = 0;
656 			TARGETDB_PRINT2((CE_WARN, "Unknown bridge!"));
657 		}
658 
659 		if (ddi_copyout(&type, (void *)data, sizeof (int), mode)) {
660 			mutex_exit(&st->tsoft_lock);
661 			return (EFAULT);
662 		}
663 
664 		break;
665 	}
666 	case I8XX_GET_PREALLOC_SIZE:
667 	{
668 		size_t prealloc_size;
669 
670 		if (!is_intel_br(st)) {
671 			mutex_exit(&st->tsoft_lock);
672 			return (EINVAL);
673 		}
674 
675 		prealloc_size = i8xx_biosmem_detect(st);
676 		if (ddi_copyout(&prealloc_size, (void *)data,
677 		    sizeof (size_t), mode)) {
678 			mutex_exit(&st->tsoft_lock);
679 			return (EFAULT);
680 		}
681 
682 		break;
683 	}
684 	case AGP_TARGET_GETINFO:
685 	{
686 		i_agp_info_t info;
687 		uint32_t value;
688 		off_t cap;
689 
690 		ASSERT(st->tsoft_acaptr);
691 
692 		cap = st->tsoft_acaptr;
693 		value = pci_config_get32(st->tsoft_pcihdl, cap);
694 		info.iagp_ver.agpv_major = (uint16_t)((value >> 20) & 0xf);
695 		info.iagp_ver.agpv_minor = (uint16_t)((value >> 16) & 0xf);
696 		info.iagp_devid = st->tsoft_devid;
697 		info.iagp_mode = pci_config_get32(st->tsoft_pcihdl,
698 		    cap + AGP_CONF_STATUS);
699 		info.iagp_aperbase = agp_target_get_apbase(st);
700 		info.iagp_apersize = agp_target_get_apsize(st);
701 
702 		if (ddi_copyout(&info, (void *)data,
703 		    sizeof (i_agp_info_t), mode)) {
704 			mutex_exit(&st->tsoft_lock);
705 			return (EFAULT);
706 		}
707 		break;
708 
709 	}
710 	/*
711 	 * This ioctl is only for Intel AGP chipsets.
712 	 * It is not necessary for the AMD8151 AGP bridge, because
713 	 * this register in the AMD8151 does not control any hardware.
714 	 * It is only provided for compatibility with an Intel AGP bridge.
715 	 * Please refer to the <<AMD8151 data sheet>> page 24,
716 	 * AGP device GART pointer.
717 	 */
718 	case AGP_TARGET_SET_GATTADDR:
719 	{
720 		uint32_t gartaddr;
721 
722 		if (ddi_copyin((void *)data, &gartaddr,
723 		    sizeof (uint32_t), mode)) {
724 			mutex_exit(&st->tsoft_lock);
725 			return (EFAULT);
726 		}
727 
728 		agp_target_set_gartaddr(st, gartaddr);
729 		break;
730 	}
731 	case AGP_TARGET_SETCMD:
732 	{
733 		uint32_t command;
734 
735 		if (ddi_copyin((void *)data, &command,
736 		    sizeof (uint32_t), mode)) {
737 			mutex_exit(&st->tsoft_lock);
738 			return (EFAULT);
739 		}
740 
741 		ASSERT(st->tsoft_acaptr);
742 
743 		pci_config_put32(st->tsoft_pcihdl,
744 		    st->tsoft_acaptr + AGP_CONF_COMMAND,
745 		    command);
746 		break;
747 
748 	}
749 	case AGP_TARGET_FLUSH_GTLB:
750 	{
751 		uint16_t value;
752 
753 		ASSERT(st->tsoft_acaptr);
754 
755 		value = pci_config_get16(st->tsoft_pcihdl,
756 		    st->tsoft_acaptr + AGP_CONF_CONTROL);
757 		value &= ~AGPCTRL_GTLBEN;
758 		pci_config_put16(st->tsoft_pcihdl,
759 		    st->tsoft_acaptr + AGP_CONF_CONTROL, value);
760 		value |= AGPCTRL_GTLBEN;
761 		pci_config_put16(st->tsoft_pcihdl,
762 		    st->tsoft_acaptr + AGP_CONF_CONTROL, value);
763 
764 		break;
765 	}
766 	case AGP_TARGET_CONFIGURE:
767 	{
768 		uint8_t value;
769 
770 		ASSERT(st->tsoft_acaptr);
771 
772 		/*
773 		 * In Intel agp bridges, agp misc register offset
774 		 * is indexed from 0 instead of capability register.
775 		 * AMD agp bridges have no such misc register
776 		 * to control the aperture access, and they have
777 		 * similar regsiters in CPU gart devices instead.
778 		 */
779 
780 		if (is_intel_br(st)) {
781 			value = pci_config_get8(st->tsoft_pcihdl,
782 			    st->tsoft_acaptr + AGP_CONF_MISC);
783 			value |= AGP_MISC_APEN;
784 			pci_config_put8(st->tsoft_pcihdl,
785 			    st->tsoft_acaptr + AGP_CONF_MISC, value);
786 		}
787 		break;
788 
789 	}
790 	case AGP_TARGET_UNCONFIG:
791 	{
792 		uint32_t value1;
793 		uint8_t value2;
794 
795 		ASSERT(st->tsoft_acaptr);
796 
797 		pci_config_put16(st->tsoft_pcihdl,
798 		    st->tsoft_acaptr + AGP_CONF_CONTROL, 0x0);
799 
800 		if (is_intel_br(st)) {
801 			value2 = pci_config_get8(st->tsoft_pcihdl,
802 			    st->tsoft_acaptr + AGP_CONF_MISC);
803 			value2 &= ~AGP_MISC_APEN;
804 			pci_config_put8(st->tsoft_pcihdl,
805 			    st->tsoft_acaptr + AGP_CONF_MISC, value2);
806 		}
807 
808 		value1 = pci_config_get32(st->tsoft_pcihdl,
809 		    st->tsoft_acaptr + AGP_CONF_COMMAND);
810 		value1 &= ~AGPCMD_AGPEN;
811 		pci_config_put32(st->tsoft_pcihdl,
812 		    st->tsoft_acaptr + AGP_CONF_COMMAND,
813 		    value1);
814 
815 		pci_config_put32(st->tsoft_pcihdl,
816 		    st->tsoft_acaptr + AGP_CONF_ATTBASE, 0x0);
817 
818 		break;
819 	}
820 
821 	case INTEL_CHIPSET_FLUSH_SETUP:
822 	case INTEL_CHIPSET_FLUSH:
823 	case INTEL_CHIPSET_FLUSH_FREE:
824 		break;
825 	default:
826 		mutex_exit(&st->tsoft_lock);
827 		return (ENXIO);
828 	} /* end switch */
829 
830 	mutex_exit(&st->tsoft_lock);
831 
832 	return (0);
833 }
834 
835 /*ARGSUSED*/
836 static int
agp_target_open(dev_t * devp,int flag,int otyp,cred_t * cred)837 agp_target_open(dev_t *devp, int flag, int otyp, cred_t *cred)
838 {
839 	int instance = DEV2INST(*devp);
840 	agp_target_softstate_t *st;
841 
842 	if (!(flag & FKLYR))
843 		return (ENXIO);
844 
845 	st = GETSOFTC(instance);
846 
847 	if (st == NULL)
848 		return (ENXIO);
849 
850 	return (0);
851 }
852 
853 /*ARGSUSED*/
854 static int
agp_target_close(dev_t dev,int flag,int otyp,cred_t * cred)855 agp_target_close(dev_t dev, int flag, int otyp, cred_t *cred)
856 {
857 	int instance = DEV2INST(dev);
858 	agp_target_softstate_t *st;
859 
860 	st = GETSOFTC(instance);
861 
862 	if (st == NULL)
863 		return (ENXIO);
864 
865 	return (0);
866 }
867 
868 static  struct  cb_ops  agp_target_cb_ops = {
869 	agp_target_open,		/* cb_open */
870 	agp_target_close,		/* cb_close */
871 	nodev,				/* cb_strategy */
872 	nodev,				/* cb_print */
873 	nodev,				/* cb_dump */
874 	nodev,				/* cb_read() */
875 	nodev,				/* cb_write() */
876 	agp_target_ioctl,		/* cb_ioctl */
877 	nodev,				/* cb_devmap */
878 	nodev,				/* cb_mmap */
879 	nodev,				/* cb_segmap */
880 	nochpoll,			/* cb_chpoll */
881 	ddi_prop_op,			/* cb_prop_op */
882 	0,				/* cb_stream */
883 	D_NEW | D_MP, 			/* cb_flag */
884 	CB_REV,				/* cb_ops version? */
885 	nodev,				/* cb_aread() */
886 	nodev,				/* cb_awrite() */
887 };
888 
889 /* device operations */
890 static struct dev_ops agp_target_ops = {
891 	DEVO_REV,		/* devo_rev */
892 	0,			/* devo_refcnt */
893 	agptarget_getinfo, 	/* devo_getinfo */
894 	nulldev,		/* devo_identify */
895 	nulldev,		/* devo_probe */
896 	agp_target_attach,	/* devo_attach */
897 	agp_target_detach,	/* devo_detach */
898 	nodev,			/* devo_reset */
899 	&agp_target_cb_ops,	/* devo_cb_ops */
900 	0,			/* devo_bus_ops */
901 	0,			/* devo_power */
902 	ddi_quiesce_not_needed,	/* devo_quiesce */
903 };
904 
905 static  struct modldrv modldrv = {
906 	&mod_driverops,
907 	"AGP target driver",
908 	&agp_target_ops,
909 };
910 
911 static  struct modlinkage modlinkage = {
912 	MODREV_1,		/* MODREV_1 is indicated by manual */
913 	{&modldrv, NULL, NULL, NULL}
914 };
915 
916 int
_init(void)917 _init(void)
918 {
919 	int ret;
920 
921 	ret = ddi_soft_state_init(&agptarget_glob_soft_handle,
922 	    sizeof (agp_target_softstate_t), 1);
923 
924 	if (ret)
925 		goto err1;
926 
927 	if ((ret = mod_install(&modlinkage)) != 0) {
928 		goto err2;
929 	}
930 
931 	return (DDI_SUCCESS);
932 err2:
933 	ddi_soft_state_fini(&agptarget_glob_soft_handle);
934 err1:
935 	return (ret);
936 }
937 
938 int
_info(struct modinfo * modinfop)939 _info(struct  modinfo *modinfop)
940 {
941 	return (mod_info(&modlinkage, modinfop));
942 }
943 
944 int
_fini(void)945 _fini(void)
946 {
947 	int	ret;
948 
949 	if ((ret = mod_remove(&modlinkage)) == 0) {
950 		ddi_soft_state_fini(&agptarget_glob_soft_handle);
951 	}
952 	return (ret);
953 }
954