xref: /onnv-gate/usr/src/uts/intel/io/agpgart/amd64_gart.c (revision 7656:2621e50fdf4a)
13446Smrj /*
27542SRichard.Bean@Sun.COM  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
33446Smrj  * Use is subject to license terms.
43446Smrj  */
53446Smrj 
63446Smrj #include <sys/conf.h>
73446Smrj #include <sys/ddi.h>
83446Smrj #include <sys/sunddi.h>
93446Smrj #include <sys/modctl.h>
103446Smrj #include <sys/stat.h>
113446Smrj #include <sys/sunldi.h>
123446Smrj #include <sys/file.h>
133446Smrj #include <sys/agpgart.h>
143446Smrj #include <sys/agp/agpdefs.h>
153446Smrj #include <sys/agp/agpamd64gart_io.h>
163446Smrj 
173446Smrj #define	MAX_GART_INSTS		8
183446Smrj #define	GETSOFTC(instance)	((amd64_gart_softstate_t *)	\
193446Smrj     ddi_get_soft_state(amd64_gart_glob_soft_handle, (instance)));
203446Smrj #define	DEV2INST(dev)		(getminor(dev))
213446Smrj #define	INST2NODENUM(inst)	(inst)
223446Smrj 
233446Smrj int amd64_debug_var = 0;
243446Smrj #define	AMD64DB_PRINT1(fmt)	if (amd64_debug_var == 1) cmn_err fmt
253446Smrj #define	AMD64DB_PRINT2(fmt)	if (amd64_debug_var >= 1) cmn_err fmt
263446Smrj 
273446Smrj typedef struct amd64_gart_softstate {
283446Smrj 	dev_info_t		*gsoft_dip;
293446Smrj 	ddi_acc_handle_t	gsoft_pcihdl;
303446Smrj 	kmutex_t		gsoft_lock;
313446Smrj }amd64_gart_softstate_t;
323446Smrj 
333446Smrj static void *amd64_gart_glob_soft_handle;
343446Smrj 
353446Smrj static uint64_t
amd64_get_aperbase(amd64_gart_softstate_t * sc)363446Smrj amd64_get_aperbase(amd64_gart_softstate_t *sc)
373446Smrj {
383446Smrj 	uint32_t	value;
393446Smrj 	uint64_t	aper_base;
403446Smrj 
413446Smrj 	/* amd64 aperture base support 40 bits and 32M aligned */
423446Smrj 	value = pci_config_get32(sc->gsoft_pcihdl,
433446Smrj 	    AMD64_APERTURE_BASE) & AMD64_APERBASE_MASK;
443446Smrj 	aper_base = (uint64_t)value << AMD64_APERBASE_SHIFT;
453446Smrj 	return (aper_base);
463446Smrj }
473446Smrj 
483446Smrj static size_t
amd64_get_apersize(amd64_gart_softstate_t * sc)493446Smrj amd64_get_apersize(amd64_gart_softstate_t *sc)
503446Smrj {
513446Smrj 	uint32_t	value;
523446Smrj 	size_t		size;
533446Smrj 
543446Smrj 	value = pci_config_get32(sc->gsoft_pcihdl, AMD64_APERTURE_CONTROL);
553446Smrj 
563446Smrj 	value = (value & AMD64_APERSIZE_MASK) >> 1;
573446Smrj 
583446Smrj 	/* aper size = 2^value x 32 */
593446Smrj 	switch (value) {
603446Smrj 		case  0x0:
613446Smrj 			size = 32;
623446Smrj 			break;
633446Smrj 		case  0x1:
643446Smrj 			size = 64;
653446Smrj 			break;
663446Smrj 		case  0x2:
673446Smrj 			size = 128;
683446Smrj 			break;
693446Smrj 		case  0x3:
703446Smrj 			size = 256;
713446Smrj 			break;
723446Smrj 		case  0x4:
733446Smrj 			size = 512;
743446Smrj 			break;
753446Smrj 		case  0x5:
763446Smrj 			size = 1024;
773446Smrj 			break;
783446Smrj 		case  0x6:
793446Smrj 			size = 2048;
803446Smrj 			break;
813446Smrj 		default:		/* reserved */
823446Smrj 			size = 0;
833446Smrj 	};
843446Smrj 
853446Smrj 	return (size);
863446Smrj }
873446Smrj 
883446Smrj static void
amd64_invalidate_gtlb(amd64_gart_softstate_t * sc)893446Smrj amd64_invalidate_gtlb(amd64_gart_softstate_t *sc)
903446Smrj {
913446Smrj 	uint32_t value;
923446Smrj 
933446Smrj 	value = pci_config_get32(sc->gsoft_pcihdl, AMD64_GART_CACHE_CTL);
943446Smrj 	value |= AMD64_INVALID_CACHE;
953446Smrj 
963446Smrj 	pci_config_put32(sc->gsoft_pcihdl, AMD64_GART_CACHE_CTL, value);
973446Smrj }
983446Smrj 
993446Smrj static void
amd64_enable_gart(amd64_gart_softstate_t * sc,int enable)1003446Smrj amd64_enable_gart(amd64_gart_softstate_t *sc, int enable)
1013446Smrj {
1023446Smrj 	uint32_t aper_ctl;
1033446Smrj 	uint32_t aper_base;
1043446Smrj 	uint32_t gart_ctl;
1053446Smrj 	uint32_t gart_base;
1063446Smrj 
1073446Smrj 	aper_ctl = pci_config_get32(sc->gsoft_pcihdl, AMD64_APERTURE_CONTROL);
1083446Smrj 	AMD64DB_PRINT1((CE_NOTE, "before: aper_ctl = %x", aper_ctl));
1093446Smrj 	aper_base = pci_config_get32(sc->gsoft_pcihdl, AMD64_APERTURE_BASE);
1103446Smrj 	gart_ctl = pci_config_get32(sc->gsoft_pcihdl, AMD64_GART_CACHE_CTL);
1113446Smrj 	gart_base = pci_config_get32(sc->gsoft_pcihdl, AMD64_GART_BASE);
1123446Smrj #ifdef lint
1133446Smrj 	aper_base = aper_base;
1143446Smrj 	gart_ctl = gart_ctl;
1153446Smrj 	gart_base = gart_base;
1163446Smrj #endif /* lint */
1173446Smrj 	AMD64DB_PRINT1((CE_NOTE, "before: aper_base = %x", aper_base));
1183446Smrj 	AMD64DB_PRINT1((CE_NOTE, "before: gart_ctl = %x", gart_ctl));
1193446Smrj 	AMD64DB_PRINT1((CE_NOTE, "before: gart_base = %x", gart_base));
1203446Smrj 	if (enable) {
1213446Smrj 		aper_ctl |= AMD64_GARTEN;
1223446Smrj 		aper_ctl &= ~(AMD64_DISGARTCPU | AMD64_DISGARTIO);
1233446Smrj 	} else
1243446Smrj 		aper_ctl &= (~AMD64_GARTEN);
1253446Smrj 
1263446Smrj 	pci_config_put32(sc->gsoft_pcihdl, AMD64_APERTURE_CONTROL, aper_ctl);
1273446Smrj }
1283446Smrj 
1293446Smrj /*ARGSUSED*/
1303446Smrj static int
amd64_gart_getinfo(dev_info_t * dip,ddi_info_cmd_t cmd,void * arg,void ** resultp)1313446Smrj amd64_gart_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd,
1323446Smrj     void *arg, void **resultp)
1333446Smrj {
1343446Smrj 	amd64_gart_softstate_t *st;
1353446Smrj 	int instance, rval = DDI_FAILURE;
1363446Smrj 	dev_t dev;
1373446Smrj 
1383446Smrj 	switch (cmd) {
1393446Smrj 	case DDI_INFO_DEVT2DEVINFO:
1403446Smrj 		dev = (dev_t)arg;
1413446Smrj 		instance = DEV2INST(dev);
1423446Smrj 		st = ddi_get_soft_state(amd64_gart_glob_soft_handle, instance);
1433446Smrj 		if (st != NULL) {
1443446Smrj 			mutex_enter(&st->gsoft_lock);
1453446Smrj 			*resultp = st->gsoft_dip;
1463446Smrj 			mutex_exit(&st->gsoft_lock);
1473446Smrj 			rval = DDI_SUCCESS;
1483446Smrj 		} else {
1493446Smrj 			*resultp = NULL;
1503446Smrj 		}
1513446Smrj 
1523446Smrj 		break;
1533446Smrj 	case DDI_INFO_DEVT2INSTANCE:
1543446Smrj 		dev = (dev_t)arg;
1553446Smrj 		instance = DEV2INST(dev);
1563446Smrj 		*resultp = (void *)(uintptr_t)instance;
1573446Smrj 		rval = DDI_SUCCESS;
1583446Smrj 		break;
1593446Smrj 	default:
1603446Smrj 		break;
1613446Smrj 	}
1623446Smrj 
1633446Smrj 	return (rval);
1643446Smrj }
1653446Smrj 
1663446Smrj static int
amd64_gart_attach(dev_info_t * dip,ddi_attach_cmd_t cmd)1673446Smrj amd64_gart_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
1683446Smrj {
1693446Smrj 	int			instance;
1703446Smrj 	amd64_gart_softstate_t	*sc;
1713446Smrj 	int			status;
1723446Smrj 	char			buf[80];
1733446Smrj 
1745295Srandyf 	switch (cmd) {
1755295Srandyf 	default:
1763446Smrj 		return (DDI_FAILURE);
1773446Smrj 
1785295Srandyf 	case DDI_RESUME:
1795295Srandyf 		/* Nothing special is needed for resume. */
1805295Srandyf 		return (DDI_SUCCESS);
1815295Srandyf 
1825295Srandyf 	case DDI_ATTACH:
1835295Srandyf 		break;
1845295Srandyf 	}
1855295Srandyf 
1863446Smrj 	instance = ddi_get_instance(dip);
1873446Smrj 
1883446Smrj 	if (ddi_soft_state_zalloc(amd64_gart_glob_soft_handle, instance) !=
1893446Smrj 	    DDI_SUCCESS)
1903446Smrj 		return (DDI_FAILURE);
1913446Smrj 
1923446Smrj 	sc = ddi_get_soft_state(amd64_gart_glob_soft_handle, instance);
1933446Smrj 	mutex_init(&sc->gsoft_lock, NULL, MUTEX_DRIVER, NULL);
1943446Smrj 	sc->gsoft_dip = dip;
1953446Smrj 	status = pci_config_setup(dip, &sc->gsoft_pcihdl);
1963446Smrj 	if (status != DDI_SUCCESS) {
1973446Smrj 		ddi_soft_state_free(amd64_gart_glob_soft_handle, instance);
1983446Smrj 		return (DDI_FAILURE);
1993446Smrj 	}
2003446Smrj 	(void) sprintf(buf, "%s-%d", AMD64GART_NAME, instance);
2013446Smrj 	status = ddi_create_minor_node(dip, buf, S_IFCHR,
2023446Smrj 	    INST2NODENUM(instance), DDI_NT_AGP_CPUGART, 0);
2033446Smrj 	if (status != DDI_SUCCESS) {
2043446Smrj 		pci_config_teardown(&sc->gsoft_pcihdl);
2053446Smrj 		ddi_soft_state_free(amd64_gart_glob_soft_handle, instance);
2063446Smrj 		return (DDI_FAILURE);
2073446Smrj 	}
2083446Smrj 	return (DDI_SUCCESS);
2093446Smrj }
2103446Smrj 
2113446Smrj /*ARGSUSED*/
2123446Smrj static int
amd64_gart_detach(dev_info_t * dip,ddi_detach_cmd_t cmd)2133446Smrj amd64_gart_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
2143446Smrj {
2153446Smrj 	int			instance;
2163446Smrj 	amd64_gart_softstate_t	*sc;
2173446Smrj 	char			buf[80];
2183446Smrj 
2195295Srandyf 	switch (cmd) {
2205295Srandyf 	default:
2213446Smrj 		return (DDI_FAILURE);
2223446Smrj 
2235295Srandyf 	case DDI_SUSPEND:
2245295Srandyf 		/* Nothing special is needed for suspend */
2255295Srandyf 		return (DDI_SUCCESS);
2265295Srandyf 
2275295Srandyf 	case DDI_DETACH:
2285295Srandyf 		break;
2295295Srandyf 	}
2305295Srandyf 
2313446Smrj 	instance = ddi_get_instance(dip);
2323446Smrj 	sc = ddi_get_soft_state(amd64_gart_glob_soft_handle, instance);
2333446Smrj 
2343446Smrj 	(void) sprintf(buf, "%s-%d", AMD64GART_NAME, instance);
2353446Smrj 	ddi_remove_minor_node(dip, buf);
2363446Smrj 	pci_config_teardown(&sc->gsoft_pcihdl);
2373446Smrj 	mutex_destroy(&sc->gsoft_lock);
2383446Smrj 	ddi_soft_state_free(amd64_gart_glob_soft_handle, instance);
2393446Smrj 
2403446Smrj 	return (DDI_SUCCESS);
2413446Smrj }
2423446Smrj 
2433446Smrj /*ARGSUSED*/
2443446Smrj static int
amd64_gart_ioctl(dev_t dev,int cmd,intptr_t data,int mode,cred_t * cred,int * rval)2453446Smrj amd64_gart_ioctl(dev_t dev, int cmd, intptr_t data, int mode,
2463446Smrj     cred_t *cred, int *rval)
2473446Smrj {
2483446Smrj 	int instance;
2493446Smrj 	amd64_gart_softstate_t *sc;
2503446Smrj 	static char kernel_only[] =
2513446Smrj 	    "amd64_gart_ioctl: is a kernel only ioctl";
2523446Smrj 
2533446Smrj 	if (!(mode & FKIOCTL)) {
2543446Smrj 		AMD64DB_PRINT2((CE_CONT, kernel_only));
2553446Smrj 		return (ENXIO);
2563446Smrj 	}
2573446Smrj 	instance = DEV2INST(dev);
2583446Smrj 	sc = GETSOFTC(instance);
2593446Smrj 
2603446Smrj 	if (sc == NULL)
2613446Smrj 		return (ENXIO);
2623446Smrj 	mutex_enter(&sc->gsoft_lock);
2633446Smrj 
2643446Smrj 	switch (cmd) {
2653446Smrj 	case AMD64_GET_INFO:
2663446Smrj 	{
2673446Smrj 		amdgart_info_t info;
2683446Smrj 
2693446Smrj 		info.cgart_aperbase = amd64_get_aperbase(sc);
2703446Smrj 		info.cgart_apersize = amd64_get_apersize(sc);
2713446Smrj 
2723446Smrj 		if (ddi_copyout(&info, (void *)data,
2733446Smrj 		    sizeof (amdgart_info_t), mode)) {
2743446Smrj 			mutex_exit(&sc->gsoft_lock);
2753446Smrj 			return (EFAULT);
2763446Smrj 		}
2773446Smrj 		break;
2783446Smrj 	}
2793446Smrj 	case AMD64_SET_GART_ADDR:
2803446Smrj 	{
2813446Smrj 		uint32_t addr;
2823446Smrj 
2833446Smrj 		if (ddi_copyin((void *)data, &addr, sizeof (uint32_t), mode)) {
2843446Smrj 			mutex_exit(&sc->gsoft_lock);
2853446Smrj 			return (EFAULT);
2863446Smrj 		}
2873446Smrj 
2883446Smrj 		pci_config_put32(sc->gsoft_pcihdl, AMD64_GART_BASE, addr);
2893446Smrj 		amd64_enable_gart(sc, 1);
2903446Smrj 
2913446Smrj 		break;
2923446Smrj 	}
2933446Smrj 	case AMD64_FLUSH_GTLB:
2943446Smrj 	{
2953446Smrj 		amd64_invalidate_gtlb(sc);
2963446Smrj 
2973446Smrj 		break;
2983446Smrj 	}
2993446Smrj 	case AMD64_CONFIGURE:
3003446Smrj 	{
3013446Smrj 		/* reserved */
3023446Smrj 		break;
3033446Smrj 	}
3043446Smrj 	case AMD64_UNCONFIG:
3053446Smrj 	{
3063446Smrj 		amd64_enable_gart(sc, 0);
3073446Smrj 		pci_config_put32(sc->gsoft_pcihdl, AMD64_GART_BASE, 0x00000000);
3083446Smrj 
3093446Smrj 		break;
3103446Smrj 	}
3113446Smrj 	default:
3123446Smrj 		mutex_exit(&sc->gsoft_lock);
3133446Smrj 		return (ENXIO);
3143446Smrj 
3153446Smrj 	}
3163446Smrj 
3173446Smrj 	mutex_exit(&sc->gsoft_lock);
3183446Smrj 
3193446Smrj 	return (0);
3203446Smrj }
3213446Smrj 
3223446Smrj /*ARGSUSED*/
3233446Smrj static int
amd64_gart_open(dev_t * dev,int flag,int otyp,cred_t * cred)3243446Smrj amd64_gart_open(dev_t *dev, int flag, int otyp, cred_t *cred)
3253446Smrj {
3263446Smrj 	int			instance;
3273446Smrj 	amd64_gart_softstate_t	*sc;
3283446Smrj 
3293446Smrj 	if (!(flag & FKLYR))
3303446Smrj 		return (ENXIO);
3313446Smrj 
3323446Smrj 	instance = DEV2INST(*dev);
3333446Smrj 	sc = GETSOFTC(instance);
3343446Smrj 
3353446Smrj 	if (sc == NULL)
3363446Smrj 		return (ENXIO);
3373446Smrj 
3383446Smrj 	return (0);
3393446Smrj }
3403446Smrj 
3413446Smrj /*ARGSUSED*/
3423446Smrj static int
amd64_gart_close(dev_t dev,int flag,int otyp,cred_t * cred)3433446Smrj amd64_gart_close(dev_t dev, int flag, int otyp, cred_t *cred)
3443446Smrj {
3453446Smrj 	int			instance;
3463446Smrj 	amd64_gart_softstate_t	*sc;
3473446Smrj 
3483446Smrj 	instance = DEV2INST(dev);
3493446Smrj 	sc = GETSOFTC(instance);
3503446Smrj 
3513446Smrj 	if (sc == NULL)
3523446Smrj 		return (ENXIO);
3533446Smrj 
3543446Smrj 	return (0);
3553446Smrj }
3563446Smrj 
3573446Smrj static  struct  cb_ops  amd64_gart_cb_ops = {
3583446Smrj 	amd64_gart_open,	/* cb_open() */
3593446Smrj 	amd64_gart_close,	/* cb_close() */
3603446Smrj 	nodev,			/* cb_strategy() */
3613446Smrj 	nodev,			/* cb_print */
3623446Smrj 	nodev,			/* cb_dump */
3633446Smrj 	nodev,			/* cb_read() */
3643446Smrj 	nodev,			/* cb_write() */
3653446Smrj 	amd64_gart_ioctl,	/* cb_ioctl */
3663446Smrj 	nodev,			/* cb_devmap */
3673446Smrj 	nodev,			/* cb_mmap */
3683446Smrj 	nodev,			/* cb_segmap */
3693446Smrj 	nochpoll,		/* cb_chpoll */
3703446Smrj 	ddi_prop_op,		/* cb_prop_op */
3713446Smrj 	0,			/* cb_stream */
3723446Smrj 	D_NEW | D_MP,		/* cb_flag */
3733446Smrj 	CB_REV,			/* cb_ops version? */
3743446Smrj 	nodev,			/* cb_aread() */
3753446Smrj 	nodev,			/* cb_awrite() */
3763446Smrj };
3773446Smrj 
3783446Smrj /* device operations */
3793446Smrj static struct dev_ops amd64_gart_ops = {
3803446Smrj 	DEVO_REV,		/* devo_rev */
3813446Smrj 	0,			/* devo_refcnt */
3823446Smrj 	amd64_gart_getinfo,	/* devo_getinfo */
3833446Smrj 	nulldev,		/* devo_identify */
3843446Smrj 	nulldev,		/* devo_probe */
3853446Smrj 	amd64_gart_attach,	/* devo_attach */
3863446Smrj 	amd64_gart_detach,	/* devo_detach */
3873446Smrj 	nodev,			/* devo_reset */
3883446Smrj 	&amd64_gart_cb_ops,	/* devo_cb_ops */
3893446Smrj 	0,			/* devo_bus_ops */
3903446Smrj 	0,			/* devo_power */
391*7656SSherry.Moore@Sun.COM 	ddi_quiesce_not_needed,	/* devo_quiesce */
3923446Smrj };
3933446Smrj 
3943446Smrj static  struct modldrv modldrv = {
3953446Smrj 	&mod_driverops,
3967542SRichard.Bean@Sun.COM 	"AGP AMD gart driver",
3973446Smrj 	&amd64_gart_ops,
3983446Smrj };
3993446Smrj 
4003446Smrj static  struct modlinkage modlinkage = {
4013446Smrj 	MODREV_1,		/* MODREV_1 is indicated by manual */
4023446Smrj 	&modldrv,
4033446Smrj 	NULL
4043446Smrj };
4053446Smrj 
4063446Smrj 
4073446Smrj int
_init(void)4083446Smrj _init(void)
4093446Smrj {
4103446Smrj 	int ret = DDI_SUCCESS;
4113446Smrj 
4123446Smrj 	ret = ddi_soft_state_init(&amd64_gart_glob_soft_handle,
4133446Smrj 	    sizeof (amd64_gart_softstate_t),
4143446Smrj 	    MAX_GART_INSTS);
4153446Smrj 
4163446Smrj 	if (ret)
4173446Smrj 		return (ret);
4183446Smrj 	if ((ret = mod_install(&modlinkage)) != 0) {
4193446Smrj 		ddi_soft_state_fini(&amd64_gart_glob_soft_handle);
4203446Smrj 		return (ret);
4213446Smrj 	}
4223446Smrj 	return (DDI_SUCCESS);
4233446Smrj }
4243446Smrj 
4253446Smrj int
_info(struct modinfo * modinfop)4263446Smrj _info(struct  modinfo *modinfop)
4273446Smrj {
4283446Smrj 	return (mod_info(&modlinkage, modinfop));
4293446Smrj }
4303446Smrj 
4313446Smrj int
_fini(void)4323446Smrj _fini(void)
4333446Smrj {
4343446Smrj 	int ret;
4353446Smrj 	if ((ret = mod_remove(&modlinkage)) == 0) {
4363446Smrj 		ddi_soft_state_fini(&amd64_gart_glob_soft_handle);
4373446Smrj 	}
4383446Smrj 	return (ret);
4393446Smrj }
440