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