xref: /titanic_50/usr/src/uts/intel/io/agpgart/amd64_gart.c (revision 711890bc9379ceea66272dc8d4981812224ea86e)
1 /*
2  * Copyright 2005 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/conf.h>
9 #include <sys/ddi.h>
10 #include <sys/sunddi.h>
11 #include <sys/modctl.h>
12 #include <sys/stat.h>
13 #include <sys/sunldi.h>
14 #include <sys/file.h>
15 #include <sys/agpgart.h>
16 #include <sys/agp/agpdefs.h>
17 #include <sys/agp/agpamd64gart_io.h>
18 
19 #define	MAX_GART_INSTS		8
20 #define	GETSOFTC(instance)	((amd64_gart_softstate_t *)	\
21     ddi_get_soft_state(amd64_gart_glob_soft_handle, (instance)));
22 #define	DEV2INST(dev)		(getminor(dev))
23 #define	INST2NODENUM(inst)	(inst)
24 
25 int amd64_debug_var = 0;
26 #define	AMD64DB_PRINT1(fmt)	if (amd64_debug_var == 1) cmn_err fmt
27 #define	AMD64DB_PRINT2(fmt)	if (amd64_debug_var >= 1) cmn_err fmt
28 
29 typedef struct amd64_gart_softstate {
30 	dev_info_t		*gsoft_dip;
31 	ddi_acc_handle_t	gsoft_pcihdl;
32 	kmutex_t		gsoft_lock;
33 }amd64_gart_softstate_t;
34 
35 static void *amd64_gart_glob_soft_handle;
36 
37 static uint64_t
38 amd64_get_aperbase(amd64_gart_softstate_t *sc)
39 {
40 	uint32_t	value;
41 	uint64_t	aper_base;
42 
43 	/* amd64 aperture base support 40 bits and 32M aligned */
44 	value = pci_config_get32(sc->gsoft_pcihdl,
45 	    AMD64_APERTURE_BASE) & AMD64_APERBASE_MASK;
46 	aper_base = (uint64_t)value << AMD64_APERBASE_SHIFT;
47 	return (aper_base);
48 }
49 
50 static size_t
51 amd64_get_apersize(amd64_gart_softstate_t *sc)
52 {
53 	uint32_t	value;
54 	size_t		size;
55 
56 	value = pci_config_get32(sc->gsoft_pcihdl, AMD64_APERTURE_CONTROL);
57 
58 	value = (value & AMD64_APERSIZE_MASK) >> 1;
59 
60 	/* aper size = 2^value x 32 */
61 	switch (value) {
62 		case  0x0:
63 			size = 32;
64 			break;
65 		case  0x1:
66 			size = 64;
67 			break;
68 		case  0x2:
69 			size = 128;
70 			break;
71 		case  0x3:
72 			size = 256;
73 			break;
74 		case  0x4:
75 			size = 512;
76 			break;
77 		case  0x5:
78 			size = 1024;
79 			break;
80 		case  0x6:
81 			size = 2048;
82 			break;
83 		default:		/* reserved */
84 			size = 0;
85 	};
86 
87 	return (size);
88 }
89 
90 static void
91 amd64_invalidate_gtlb(amd64_gart_softstate_t *sc)
92 {
93 	uint32_t value;
94 
95 	value = pci_config_get32(sc->gsoft_pcihdl, AMD64_GART_CACHE_CTL);
96 	value |= AMD64_INVALID_CACHE;
97 
98 	pci_config_put32(sc->gsoft_pcihdl, AMD64_GART_CACHE_CTL, value);
99 }
100 
101 static void
102 amd64_enable_gart(amd64_gart_softstate_t *sc, int enable)
103 {
104 	uint32_t aper_ctl;
105 	uint32_t aper_base;
106 	uint32_t gart_ctl;
107 	uint32_t gart_base;
108 
109 	aper_ctl = pci_config_get32(sc->gsoft_pcihdl, AMD64_APERTURE_CONTROL);
110 	AMD64DB_PRINT1((CE_NOTE, "before: aper_ctl = %x", aper_ctl));
111 	aper_base = pci_config_get32(sc->gsoft_pcihdl, AMD64_APERTURE_BASE);
112 	gart_ctl = pci_config_get32(sc->gsoft_pcihdl, AMD64_GART_CACHE_CTL);
113 	gart_base = pci_config_get32(sc->gsoft_pcihdl, AMD64_GART_BASE);
114 #ifdef lint
115 	aper_base = aper_base;
116 	gart_ctl = gart_ctl;
117 	gart_base = gart_base;
118 #endif /* lint */
119 	AMD64DB_PRINT1((CE_NOTE, "before: aper_base = %x", aper_base));
120 	AMD64DB_PRINT1((CE_NOTE, "before: gart_ctl = %x", gart_ctl));
121 	AMD64DB_PRINT1((CE_NOTE, "before: gart_base = %x", gart_base));
122 	if (enable) {
123 		aper_ctl |= AMD64_GARTEN;
124 		aper_ctl &= ~(AMD64_DISGARTCPU | AMD64_DISGARTIO);
125 	} else
126 		aper_ctl &= (~AMD64_GARTEN);
127 
128 	pci_config_put32(sc->gsoft_pcihdl, AMD64_APERTURE_CONTROL, aper_ctl);
129 }
130 
131 /*ARGSUSED*/
132 static int
133 amd64_gart_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd,
134     void *arg, void **resultp)
135 {
136 	amd64_gart_softstate_t *st;
137 	int instance, rval = DDI_FAILURE;
138 	dev_t dev;
139 
140 	switch (cmd) {
141 	case DDI_INFO_DEVT2DEVINFO:
142 		dev = (dev_t)arg;
143 		instance = DEV2INST(dev);
144 		st = ddi_get_soft_state(amd64_gart_glob_soft_handle, instance);
145 		if (st != NULL) {
146 			mutex_enter(&st->gsoft_lock);
147 			*resultp = st->gsoft_dip;
148 			mutex_exit(&st->gsoft_lock);
149 			rval = DDI_SUCCESS;
150 		} else {
151 			*resultp = NULL;
152 		}
153 
154 		break;
155 	case DDI_INFO_DEVT2INSTANCE:
156 		dev = (dev_t)arg;
157 		instance = DEV2INST(dev);
158 		*resultp = (void *)(uintptr_t)instance;
159 		rval = DDI_SUCCESS;
160 		break;
161 	default:
162 		break;
163 	}
164 
165 	return (rval);
166 }
167 
168 static int
169 amd64_gart_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
170 {
171 	int			instance;
172 	amd64_gart_softstate_t	*sc;
173 	int			status;
174 	char			buf[80];
175 
176 	if (cmd != DDI_ATTACH)
177 		return (DDI_FAILURE);
178 
179 	instance = ddi_get_instance(dip);
180 
181 	if (ddi_soft_state_zalloc(amd64_gart_glob_soft_handle, instance) !=
182 	    DDI_SUCCESS)
183 		return (DDI_FAILURE);
184 
185 	sc = ddi_get_soft_state(amd64_gart_glob_soft_handle, instance);
186 	mutex_init(&sc->gsoft_lock, NULL, MUTEX_DRIVER, NULL);
187 	sc->gsoft_dip = dip;
188 	status = pci_config_setup(dip, &sc->gsoft_pcihdl);
189 	if (status != DDI_SUCCESS) {
190 		ddi_soft_state_free(amd64_gart_glob_soft_handle, instance);
191 		return (DDI_FAILURE);
192 	}
193 	(void) sprintf(buf, "%s-%d", AMD64GART_NAME, instance);
194 	status = ddi_create_minor_node(dip, buf, S_IFCHR,
195 	    INST2NODENUM(instance), DDI_NT_AGP_CPUGART, 0);
196 	if (status != DDI_SUCCESS) {
197 		pci_config_teardown(&sc->gsoft_pcihdl);
198 		ddi_soft_state_free(amd64_gart_glob_soft_handle, instance);
199 		return (DDI_FAILURE);
200 	}
201 	return (DDI_SUCCESS);
202 }
203 
204 /*ARGSUSED*/
205 static int
206 amd64_gart_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
207 {
208 	int			instance;
209 	amd64_gart_softstate_t	*sc;
210 	char			buf[80];
211 
212 	if (cmd != DDI_DETACH)
213 		return (DDI_FAILURE);
214 
215 	instance = ddi_get_instance(dip);
216 	sc = ddi_get_soft_state(amd64_gart_glob_soft_handle, instance);
217 
218 	(void) sprintf(buf, "%s-%d", AMD64GART_NAME, instance);
219 	ddi_remove_minor_node(dip, buf);
220 	pci_config_teardown(&sc->gsoft_pcihdl);
221 	mutex_destroy(&sc->gsoft_lock);
222 	ddi_soft_state_free(amd64_gart_glob_soft_handle, instance);
223 
224 	return (DDI_SUCCESS);
225 }
226 
227 /*ARGSUSED*/
228 static int
229 amd64_gart_ioctl(dev_t dev, int cmd, intptr_t data, int mode,
230     cred_t *cred, int *rval)
231 {
232 	int instance;
233 	amd64_gart_softstate_t *sc;
234 	static char kernel_only[] =
235 	    "amd64_gart_ioctl: is a kernel only ioctl";
236 
237 	if (!(mode & FKIOCTL)) {
238 		AMD64DB_PRINT2((CE_CONT, kernel_only));
239 		return (ENXIO);
240 	}
241 	instance = DEV2INST(dev);
242 	sc = GETSOFTC(instance);
243 
244 	if (sc == NULL)
245 		return (ENXIO);
246 	mutex_enter(&sc->gsoft_lock);
247 
248 	switch (cmd) {
249 	case AMD64_GET_INFO:
250 	{
251 		amdgart_info_t info;
252 
253 		info.cgart_aperbase = amd64_get_aperbase(sc);
254 		info.cgart_apersize = amd64_get_apersize(sc);
255 
256 		if (ddi_copyout(&info, (void *)data,
257 		    sizeof (amdgart_info_t), mode)) {
258 			mutex_exit(&sc->gsoft_lock);
259 			return (EFAULT);
260 		}
261 		break;
262 	}
263 	case AMD64_SET_GART_ADDR:
264 	{
265 		uint32_t addr;
266 
267 		if (ddi_copyin((void *)data, &addr, sizeof (uint32_t), mode)) {
268 			mutex_exit(&sc->gsoft_lock);
269 			return (EFAULT);
270 		}
271 
272 		pci_config_put32(sc->gsoft_pcihdl, AMD64_GART_BASE, addr);
273 		amd64_enable_gart(sc, 1);
274 
275 		break;
276 	}
277 	case AMD64_FLUSH_GTLB:
278 	{
279 		amd64_invalidate_gtlb(sc);
280 
281 		break;
282 	}
283 	case AMD64_CONFIGURE:
284 	{
285 		/* reserved */
286 		break;
287 	}
288 	case AMD64_UNCONFIG:
289 	{
290 		amd64_enable_gart(sc, 0);
291 		pci_config_put32(sc->gsoft_pcihdl, AMD64_GART_BASE, 0x00000000);
292 
293 		break;
294 	}
295 	default:
296 		mutex_exit(&sc->gsoft_lock);
297 		return (ENXIO);
298 
299 	}
300 
301 	mutex_exit(&sc->gsoft_lock);
302 
303 	return (0);
304 }
305 
306 /*ARGSUSED*/
307 static int
308 amd64_gart_open(dev_t *dev, int flag, int otyp, cred_t *cred)
309 {
310 	int			instance;
311 	amd64_gart_softstate_t	*sc;
312 
313 	if (!(flag & FKLYR))
314 		return (ENXIO);
315 
316 	instance = DEV2INST(*dev);
317 	sc = GETSOFTC(instance);
318 
319 	if (sc == NULL)
320 		return (ENXIO);
321 
322 	return (0);
323 }
324 
325 /*ARGSUSED*/
326 static int
327 amd64_gart_close(dev_t dev, int flag, int otyp, cred_t *cred)
328 {
329 	int			instance;
330 	amd64_gart_softstate_t	*sc;
331 
332 	instance = DEV2INST(dev);
333 	sc = GETSOFTC(instance);
334 
335 	if (sc == NULL)
336 		return (ENXIO);
337 
338 	return (0);
339 }
340 
341 static  struct  cb_ops  amd64_gart_cb_ops = {
342 	amd64_gart_open,	/* cb_open() */
343 	amd64_gart_close,	/* cb_close() */
344 	nodev,			/* cb_strategy() */
345 	nodev,			/* cb_print */
346 	nodev,			/* cb_dump */
347 	nodev,			/* cb_read() */
348 	nodev,			/* cb_write() */
349 	amd64_gart_ioctl,	/* cb_ioctl */
350 	nodev,			/* cb_devmap */
351 	nodev,			/* cb_mmap */
352 	nodev,			/* cb_segmap */
353 	nochpoll,		/* cb_chpoll */
354 	ddi_prop_op,		/* cb_prop_op */
355 	0,			/* cb_stream */
356 	D_NEW | D_MP,		/* cb_flag */
357 	CB_REV,			/* cb_ops version? */
358 	nodev,			/* cb_aread() */
359 	nodev,			/* cb_awrite() */
360 };
361 
362 /* device operations */
363 static struct dev_ops amd64_gart_ops = {
364 	DEVO_REV,		/* devo_rev */
365 	0,			/* devo_refcnt */
366 	amd64_gart_getinfo,	/* devo_getinfo */
367 	nulldev,		/* devo_identify */
368 	nulldev,		/* devo_probe */
369 	amd64_gart_attach,	/* devo_attach */
370 	amd64_gart_detach,	/* devo_detach */
371 	nodev,			/* devo_reset */
372 	&amd64_gart_cb_ops,	/* devo_cb_ops */
373 	0,			/* devo_bus_ops */
374 	0,			/* devo_power */
375 };
376 
377 static  struct modldrv modldrv = {
378 	&mod_driverops,
379 	"AGP AMD gart driver v%I%",
380 	&amd64_gart_ops,
381 };
382 
383 static  struct modlinkage modlinkage = {
384 	MODREV_1,		/* MODREV_1 is indicated by manual */
385 	&modldrv,
386 	NULL
387 };
388 
389 
390 int
391 _init(void)
392 {
393 	int ret = DDI_SUCCESS;
394 
395 	ret = ddi_soft_state_init(&amd64_gart_glob_soft_handle,
396 	    sizeof (amd64_gart_softstate_t),
397 	    MAX_GART_INSTS);
398 
399 	if (ret)
400 		return (ret);
401 	if ((ret = mod_install(&modlinkage)) != 0) {
402 		ddi_soft_state_fini(&amd64_gart_glob_soft_handle);
403 		return (ret);
404 	}
405 	return (DDI_SUCCESS);
406 }
407 
408 int
409 _info(struct  modinfo *modinfop)
410 {
411 	return (mod_info(&modlinkage, modinfop));
412 }
413 
414 int
415 _fini(void)
416 {
417 	int ret;
418 	if ((ret = mod_remove(&modlinkage)) == 0) {
419 		ddi_soft_state_fini(&amd64_gart_glob_soft_handle);
420 	}
421 	return (ret);
422 }
423