2 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
3 * Use is subject to license terms.
8 #include <sys/sunddi.h>
9 #include <sys/modctl.h>
11 #include <sys/sunldi.h>
13 #include <sys/agpgart.h>
14 #include <sys/agp/agpdefs.h>
15 #include <sys/agp/agpamd64gart_io.h>
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)
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
27 typedef struct amd64_gart_softstate
{
28 dev_info_t
*gsoft_dip
;
29 ddi_acc_handle_t gsoft_pcihdl
;
31 }amd64_gart_softstate_t
;
33 static void *amd64_gart_glob_soft_handle
;
36 amd64_get_aperbase(amd64_gart_softstate_t
*sc
)
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
;
49 amd64_get_apersize(amd64_gart_softstate_t
*sc
)
54 value
= pci_config_get32(sc
->gsoft_pcihdl
, AMD64_APERTURE_CONTROL
);
56 value
= (value
& AMD64_APERSIZE_MASK
) >> 1;
58 /* aper size = 2^value x 32 */
81 default: /* reserved */
89 amd64_invalidate_gtlb(amd64_gart_softstate_t
*sc
)
93 value
= pci_config_get32(sc
->gsoft_pcihdl
, AMD64_GART_CACHE_CTL
);
94 value
|= AMD64_INVALID_CACHE
;
96 pci_config_put32(sc
->gsoft_pcihdl
, AMD64_GART_CACHE_CTL
, value
);
100 amd64_enable_gart(amd64_gart_softstate_t
*sc
, int enable
)
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
);
113 aper_base
= aper_base
;
115 gart_base
= gart_base
;
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
));
121 aper_ctl
|= AMD64_GARTEN
;
122 aper_ctl
&= ~(AMD64_DISGARTCPU
| AMD64_DISGARTIO
);
124 aper_ctl
&= (~AMD64_GARTEN
);
126 pci_config_put32(sc
->gsoft_pcihdl
, AMD64_APERTURE_CONTROL
, aper_ctl
);
131 amd64_gart_getinfo(dev_info_t
*dip
, ddi_info_cmd_t cmd
,
132 void *arg
, void **resultp
)
134 amd64_gart_softstate_t
*st
;
135 int instance
, rval
= DDI_FAILURE
;
139 case DDI_INFO_DEVT2DEVINFO
:
141 instance
= DEV2INST(dev
);
142 st
= ddi_get_soft_state(amd64_gart_glob_soft_handle
, instance
);
144 mutex_enter(&st
->gsoft_lock
);
145 *resultp
= st
->gsoft_dip
;
146 mutex_exit(&st
->gsoft_lock
);
153 case DDI_INFO_DEVT2INSTANCE
:
155 instance
= DEV2INST(dev
);
156 *resultp
= (void *)(uintptr_t)instance
;
167 amd64_gart_attach(dev_info_t
*dip
, ddi_attach_cmd_t cmd
)
170 amd64_gart_softstate_t
*sc
;
176 return (DDI_FAILURE
);
179 /* Nothing special is needed for resume. */
180 return (DDI_SUCCESS
);
186 instance
= ddi_get_instance(dip
);
188 if (ddi_soft_state_zalloc(amd64_gart_glob_soft_handle
, instance
) !=
190 return (DDI_FAILURE
);
192 sc
= ddi_get_soft_state(amd64_gart_glob_soft_handle
, instance
);
193 mutex_init(&sc
->gsoft_lock
, NULL
, MUTEX_DRIVER
, NULL
);
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
);
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
);
208 return (DDI_SUCCESS
);
213 amd64_gart_detach(dev_info_t
*dip
, ddi_detach_cmd_t cmd
)
216 amd64_gart_softstate_t
*sc
;
221 return (DDI_FAILURE
);
224 /* Nothing special is needed for suspend */
225 return (DDI_SUCCESS
);
231 instance
= ddi_get_instance(dip
);
232 sc
= ddi_get_soft_state(amd64_gart_glob_soft_handle
, instance
);
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
);
240 return (DDI_SUCCESS
);
245 amd64_gart_ioctl(dev_t dev
, int cmd
, intptr_t data
, int mode
,
246 cred_t
*cred
, int *rval
)
249 amd64_gart_softstate_t
*sc
;
250 static char kernel_only
[] =
251 "amd64_gart_ioctl: is a kernel only ioctl";
253 if (!(mode
& FKIOCTL
)) {
254 AMD64DB_PRINT2((CE_CONT
, kernel_only
));
257 instance
= DEV2INST(dev
);
258 sc
= GETSOFTC(instance
);
262 mutex_enter(&sc
->gsoft_lock
);
269 info
.cgart_aperbase
= amd64_get_aperbase(sc
);
270 info
.cgart_apersize
= amd64_get_apersize(sc
);
272 if (ddi_copyout(&info
, (void *)data
,
273 sizeof (amdgart_info_t
), mode
)) {
274 mutex_exit(&sc
->gsoft_lock
);
279 case AMD64_SET_GART_ADDR
:
283 if (ddi_copyin((void *)data
, &addr
, sizeof (uint32_t), mode
)) {
284 mutex_exit(&sc
->gsoft_lock
);
288 pci_config_put32(sc
->gsoft_pcihdl
, AMD64_GART_BASE
, addr
);
289 amd64_enable_gart(sc
, 1);
293 case AMD64_FLUSH_GTLB
:
295 amd64_invalidate_gtlb(sc
);
299 case AMD64_CONFIGURE
:
306 amd64_enable_gart(sc
, 0);
307 pci_config_put32(sc
->gsoft_pcihdl
, AMD64_GART_BASE
, 0x00000000);
312 mutex_exit(&sc
->gsoft_lock
);
317 mutex_exit(&sc
->gsoft_lock
);
324 amd64_gart_open(dev_t
*dev
, int flag
, int otyp
, cred_t
*cred
)
327 amd64_gart_softstate_t
*sc
;
332 instance
= DEV2INST(*dev
);
333 sc
= GETSOFTC(instance
);
343 amd64_gart_close(dev_t dev
, int flag
, int otyp
, cred_t
*cred
)
346 amd64_gart_softstate_t
*sc
;
348 instance
= DEV2INST(dev
);
349 sc
= GETSOFTC(instance
);
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 */
363 nodev
, /* cb_read() */
364 nodev
, /* cb_write() */
365 amd64_gart_ioctl
, /* cb_ioctl */
366 nodev
, /* cb_devmap */
368 nodev
, /* cb_segmap */
369 nochpoll
, /* cb_chpoll */
370 ddi_prop_op
, /* cb_prop_op */
372 D_NEW
| D_MP
, /* cb_flag */
373 CB_REV
, /* cb_ops version? */
374 nodev
, /* cb_aread() */
375 nodev
, /* cb_awrite() */
378 /* device operations */
379 static struct dev_ops amd64_gart_ops
= {
380 DEVO_REV
, /* devo_rev */
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 */
391 ddi_quiesce_not_needed
, /* devo_quiesce */
394 static struct modldrv modldrv
= {
396 "AGP AMD gart driver",
400 static struct modlinkage modlinkage
= {
401 MODREV_1
, /* MODREV_1 is indicated by manual */
410 int ret
= DDI_SUCCESS
;
412 ret
= ddi_soft_state_init(&amd64_gart_glob_soft_handle
,
413 sizeof (amd64_gart_softstate_t
),
418 if ((ret
= mod_install(&modlinkage
)) != 0) {
419 ddi_soft_state_fini(&amd64_gart_glob_soft_handle
);
422 return (DDI_SUCCESS
);
426 _info(struct modinfo
*modinfop
)
428 return (mod_info(&modlinkage
, modinfop
));
435 if ((ret
= mod_remove(&modlinkage
)) == 0) {
436 ddi_soft_state_fini(&amd64_gart_glob_soft_handle
);