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
amd64_get_aperbase(amd64_gart_softstate_t * sc)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
amd64_get_apersize(amd64_gart_softstate_t * sc)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
amd64_invalidate_gtlb(amd64_gart_softstate_t * sc)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
amd64_enable_gart(amd64_gart_softstate_t * sc,int enable)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
amd64_gart_getinfo(dev_info_t * dip,ddi_info_cmd_t cmd,void * arg,void ** resultp)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
amd64_gart_attach(dev_info_t * dip,ddi_attach_cmd_t cmd)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
amd64_gart_detach(dev_info_t * dip,ddi_detach_cmd_t cmd)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
amd64_gart_ioctl(dev_t dev,int cmd,intptr_t data,int mode,cred_t * cred,int * rval)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
amd64_gart_open(dev_t * dev,int flag,int otyp,cred_t * cred)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
amd64_gart_close(dev_t dev,int flag,int otyp,cred_t * cred)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
_init(void)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
_info(struct modinfo * modinfop)426 _info(struct modinfo *modinfop)
427 {
428 return (mod_info(&modlinkage, modinfop));
429 }
430
431 int
_fini(void)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