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