xref: /titanic_50/usr/src/uts/intel/io/agpgart/amd64_gart.c (revision fb60e41df3cdb2164356bc09f05d3b842c1a8365)
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/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 	switch (cmd) {
177 	default:
178 		return (DDI_FAILURE);
179 
180 	case DDI_RESUME:
181 		/* Nothing special is needed for resume. */
182 		return (DDI_SUCCESS);
183 
184 	case DDI_ATTACH:
185 		break;
186 	}
187 
188 	instance = ddi_get_instance(dip);
189 
190 	if (ddi_soft_state_zalloc(amd64_gart_glob_soft_handle, instance) !=
191 	    DDI_SUCCESS)
192 		return (DDI_FAILURE);
193 
194 	sc = ddi_get_soft_state(amd64_gart_glob_soft_handle, instance);
195 	mutex_init(&sc->gsoft_lock, NULL, MUTEX_DRIVER, NULL);
196 	sc->gsoft_dip = dip;
197 	status = pci_config_setup(dip, &sc->gsoft_pcihdl);
198 	if (status != DDI_SUCCESS) {
199 		ddi_soft_state_free(amd64_gart_glob_soft_handle, instance);
200 		return (DDI_FAILURE);
201 	}
202 	(void) sprintf(buf, "%s-%d", AMD64GART_NAME, instance);
203 	status = ddi_create_minor_node(dip, buf, S_IFCHR,
204 	    INST2NODENUM(instance), DDI_NT_AGP_CPUGART, 0);
205 	if (status != DDI_SUCCESS) {
206 		pci_config_teardown(&sc->gsoft_pcihdl);
207 		ddi_soft_state_free(amd64_gart_glob_soft_handle, instance);
208 		return (DDI_FAILURE);
209 	}
210 	return (DDI_SUCCESS);
211 }
212 
213 /*ARGSUSED*/
214 static int
215 amd64_gart_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
216 {
217 	int			instance;
218 	amd64_gart_softstate_t	*sc;
219 	char			buf[80];
220 
221 	switch (cmd) {
222 	default:
223 		return (DDI_FAILURE);
224 
225 	case DDI_SUSPEND:
226 		/* Nothing special is needed for suspend */
227 		return (DDI_SUCCESS);
228 
229 	case DDI_DETACH:
230 		break;
231 	}
232 
233 	instance = ddi_get_instance(dip);
234 	sc = ddi_get_soft_state(amd64_gart_glob_soft_handle, instance);
235 
236 	(void) sprintf(buf, "%s-%d", AMD64GART_NAME, instance);
237 	ddi_remove_minor_node(dip, buf);
238 	pci_config_teardown(&sc->gsoft_pcihdl);
239 	mutex_destroy(&sc->gsoft_lock);
240 	ddi_soft_state_free(amd64_gart_glob_soft_handle, instance);
241 
242 	return (DDI_SUCCESS);
243 }
244 
245 /*ARGSUSED*/
246 static int
247 amd64_gart_ioctl(dev_t dev, int cmd, intptr_t data, int mode,
248     cred_t *cred, int *rval)
249 {
250 	int instance;
251 	amd64_gart_softstate_t *sc;
252 	static char kernel_only[] =
253 	    "amd64_gart_ioctl: is a kernel only ioctl";
254 
255 	if (!(mode & FKIOCTL)) {
256 		AMD64DB_PRINT2((CE_CONT, kernel_only));
257 		return (ENXIO);
258 	}
259 	instance = DEV2INST(dev);
260 	sc = GETSOFTC(instance);
261 
262 	if (sc == NULL)
263 		return (ENXIO);
264 	mutex_enter(&sc->gsoft_lock);
265 
266 	switch (cmd) {
267 	case AMD64_GET_INFO:
268 	{
269 		amdgart_info_t info;
270 
271 		info.cgart_aperbase = amd64_get_aperbase(sc);
272 		info.cgart_apersize = amd64_get_apersize(sc);
273 
274 		if (ddi_copyout(&info, (void *)data,
275 		    sizeof (amdgart_info_t), mode)) {
276 			mutex_exit(&sc->gsoft_lock);
277 			return (EFAULT);
278 		}
279 		break;
280 	}
281 	case AMD64_SET_GART_ADDR:
282 	{
283 		uint32_t addr;
284 
285 		if (ddi_copyin((void *)data, &addr, sizeof (uint32_t), mode)) {
286 			mutex_exit(&sc->gsoft_lock);
287 			return (EFAULT);
288 		}
289 
290 		pci_config_put32(sc->gsoft_pcihdl, AMD64_GART_BASE, addr);
291 		amd64_enable_gart(sc, 1);
292 
293 		break;
294 	}
295 	case AMD64_FLUSH_GTLB:
296 	{
297 		amd64_invalidate_gtlb(sc);
298 
299 		break;
300 	}
301 	case AMD64_CONFIGURE:
302 	{
303 		/* reserved */
304 		break;
305 	}
306 	case AMD64_UNCONFIG:
307 	{
308 		amd64_enable_gart(sc, 0);
309 		pci_config_put32(sc->gsoft_pcihdl, AMD64_GART_BASE, 0x00000000);
310 
311 		break;
312 	}
313 	default:
314 		mutex_exit(&sc->gsoft_lock);
315 		return (ENXIO);
316 
317 	}
318 
319 	mutex_exit(&sc->gsoft_lock);
320 
321 	return (0);
322 }
323 
324 /*ARGSUSED*/
325 static int
326 amd64_gart_open(dev_t *dev, int flag, int otyp, cred_t *cred)
327 {
328 	int			instance;
329 	amd64_gart_softstate_t	*sc;
330 
331 	if (!(flag & FKLYR))
332 		return (ENXIO);
333 
334 	instance = DEV2INST(*dev);
335 	sc = GETSOFTC(instance);
336 
337 	if (sc == NULL)
338 		return (ENXIO);
339 
340 	return (0);
341 }
342 
343 /*ARGSUSED*/
344 static int
345 amd64_gart_close(dev_t dev, int flag, int otyp, cred_t *cred)
346 {
347 	int			instance;
348 	amd64_gart_softstate_t	*sc;
349 
350 	instance = DEV2INST(dev);
351 	sc = GETSOFTC(instance);
352 
353 	if (sc == NULL)
354 		return (ENXIO);
355 
356 	return (0);
357 }
358 
359 static  struct  cb_ops  amd64_gart_cb_ops = {
360 	amd64_gart_open,	/* cb_open() */
361 	amd64_gart_close,	/* cb_close() */
362 	nodev,			/* cb_strategy() */
363 	nodev,			/* cb_print */
364 	nodev,			/* cb_dump */
365 	nodev,			/* cb_read() */
366 	nodev,			/* cb_write() */
367 	amd64_gart_ioctl,	/* cb_ioctl */
368 	nodev,			/* cb_devmap */
369 	nodev,			/* cb_mmap */
370 	nodev,			/* cb_segmap */
371 	nochpoll,		/* cb_chpoll */
372 	ddi_prop_op,		/* cb_prop_op */
373 	0,			/* cb_stream */
374 	D_NEW | D_MP,		/* cb_flag */
375 	CB_REV,			/* cb_ops version? */
376 	nodev,			/* cb_aread() */
377 	nodev,			/* cb_awrite() */
378 };
379 
380 /* device operations */
381 static struct dev_ops amd64_gart_ops = {
382 	DEVO_REV,		/* devo_rev */
383 	0,			/* devo_refcnt */
384 	amd64_gart_getinfo,	/* devo_getinfo */
385 	nulldev,		/* devo_identify */
386 	nulldev,		/* devo_probe */
387 	amd64_gart_attach,	/* devo_attach */
388 	amd64_gart_detach,	/* devo_detach */
389 	nodev,			/* devo_reset */
390 	&amd64_gart_cb_ops,	/* devo_cb_ops */
391 	0,			/* devo_bus_ops */
392 	0,			/* devo_power */
393 };
394 
395 static  struct modldrv modldrv = {
396 	&mod_driverops,
397 	"AGP AMD gart driver v%I%",
398 	&amd64_gart_ops,
399 };
400 
401 static  struct modlinkage modlinkage = {
402 	MODREV_1,		/* MODREV_1 is indicated by manual */
403 	&modldrv,
404 	NULL
405 };
406 
407 
408 int
409 _init(void)
410 {
411 	int ret = DDI_SUCCESS;
412 
413 	ret = ddi_soft_state_init(&amd64_gart_glob_soft_handle,
414 	    sizeof (amd64_gart_softstate_t),
415 	    MAX_GART_INSTS);
416 
417 	if (ret)
418 		return (ret);
419 	if ((ret = mod_install(&modlinkage)) != 0) {
420 		ddi_soft_state_fini(&amd64_gart_glob_soft_handle);
421 		return (ret);
422 	}
423 	return (DDI_SUCCESS);
424 }
425 
426 int
427 _info(struct  modinfo *modinfop)
428 {
429 	return (mod_info(&modlinkage, modinfop));
430 }
431 
432 int
433 _fini(void)
434 {
435 	int ret;
436 	if ((ret = mod_remove(&modlinkage)) == 0) {
437 		ddi_soft_state_fini(&amd64_gart_glob_soft_handle);
438 	}
439 	return (ret);
440 }
441