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