1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21
22 /*
23 * Copyright (c) 2009, Intel Corporation.
24 * All Rights Reserved.
25 */
26
27 /*
28 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
29 * Use is subject to license terms.
30 */
31
32 /*
33 * Misc module for AGP master device support
34 */
35
36 #include <sys/modctl.h>
37 #include <sys/pci.h>
38 #include <sys/stat.h>
39 #include <sys/file.h>
40 #include <sys/types.h>
41 #include <sys/dditypes.h>
42 #include <sys/sunddi.h>
43 #include <sys/agpgart.h>
44 #include <sys/agp/agpdefs.h>
45 #include <sys/agp/agpmaster_io.h>
46
47 #define PGTBL_CTL 0x2020 /* Page table control register */
48 #define I8XX_FB_BAR 1
49 #define I8XX_MMIO_BAR 2
50 #define I8XX_PTE_OFFSET 0x10000
51 #define I915_MMADR 1 /* mem-mapped registers BAR */
52 #define I915_GMADR 3 /* graphics mem BAR */
53 #define I915_GTTADDR 4 /* GTT BAR */
54 #define I965_GTTMMADR 1 /* mem-mapped registers BAR + GTT */
55 /* In 965 1MB GTTMMADR, GTT reside in the latter 512KB */
56 #define I965_GTT_OFFSET 0x80000
57 #define GM45_GTT_OFFSET 0x200000
58 #define GTT_SIZE_MASK 0xe
59 #define GTT_512KB (0 << 1)
60 #define GTT_256KB (1 << 1)
61 #define GTT_128KB (2 << 1)
62 #define GTT_1MB (3 << 1)
63 #define GTT_2MB (4 << 1)
64 #define GTT_1_5MB (5 << 1)
65
66 #define MMIO_BASE(x) (x)->agpm_data.agpm_gtt.gtt_mmio_base
67 #define MMIO_HANDLE(x) (x)->agpm_data.agpm_gtt.gtt_mmio_handle
68 #define GTT_HANDLE(x) (x)->agpm_data.agpm_gtt.gtt_handle
69 /* Base address of GTT */
70 #define GTT_ADDR(x) (x)->agpm_data.agpm_gtt.gtt_addr
71 /* Graphics memory base address */
72 #define APER_BASE(x) (x)->agpm_data.agpm_gtt.gtt_info.igd_aperbase
73
74 #define AGPM_WRITE(x, off, val) \
75 ddi_put32(MMIO_HANDLE(x), (uint32_t *)(MMIO_BASE(x) + (off)), (val));
76
77 #define AGPM_READ(x, off) \
78 ddi_get32(MMIO_HANDLE(x), (uint32_t *)(MMIO_BASE(x) + (off)));
79
80 #ifdef DEBUG
81 #define CONFIRM(value) ASSERT(value)
82 #else
83 #define CONFIRM(value) if (!(value)) return (EINVAL)
84 #endif
85
86 int agpm_debug = 0;
87 #define AGPM_DEBUG(args) if (agpm_debug >= 1) cmn_err args
88
89 /*
90 * Whether it is a Intel integrated graphics card
91 */
92 #define IS_IGD(agpmaster) ((agpmaster->agpm_dev_type == DEVICE_IS_I810) || \
93 (agpmaster->agpm_dev_type == DEVICE_IS_I830))
94
95 static struct modlmisc modlmisc = {
96 &mod_miscops, "AGP master interfaces"
97 };
98
99 static struct modlinkage modlinkage = {
100 MODREV_1, (void *)&modlmisc, NULL
101 };
102
103 static ddi_device_acc_attr_t i8xx_dev_access = {
104 DDI_DEVICE_ATTR_V0,
105 DDI_NEVERSWAP_ACC,
106 DDI_STRICTORDER_ACC
107 };
108
109 static off_t agpmaster_cap_find(ddi_acc_handle_t);
110 static int detect_i8xx_device(agp_master_softc_t *);
111 static int detect_agp_devcice(agp_master_softc_t *, ddi_acc_handle_t);
112 static int i8xx_add_to_gtt(gtt_impl_t *, igd_gtt_seg_t);
113 static void i8xx_remove_from_gtt(gtt_impl_t *, igd_gtt_seg_t);
114 static int i8xx_read_gtt(gtt_impl_t *, igd_gtt_seg_t);
115 static int i8xx_write_gtt(gtt_impl_t *, igd_gtt_seg_t);
116
117 int
_init(void)118 _init(void)
119 {
120 int err;
121
122 if ((err = mod_install(&modlinkage)) != 0)
123 return (err);
124
125 return (0);
126 }
127
128 int
_fini(void)129 _fini(void)
130 {
131 int err;
132
133 if ((err = mod_remove(&modlinkage)) != 0)
134 return (err);
135
136 return (0);
137 }
138
139 int
_info(struct modinfo * modinfop)140 _info(struct modinfo *modinfop)
141 {
142 return (mod_info(&modlinkage, modinfop));
143 }
144
145 /*
146 * Minor node is not removed here, since the caller (xx_attach) is
147 * responsible for removing all nodes.
148 */
149 void
agpmaster_detach(agp_master_softc_t ** master_softcp)150 agpmaster_detach(agp_master_softc_t **master_softcp)
151 {
152 agp_master_softc_t *master_softc;
153
154 ASSERT(master_softcp);
155 master_softc = *master_softcp;
156
157 /* intel integrated device */
158 if (IS_IGD(master_softc) &&
159 ((MMIO_HANDLE(master_softc) != NULL) ||
160 (GTT_HANDLE(master_softc) != NULL))) {
161 /*
162 * for some chipsets, mmap handle is shared between both mmio
163 * and GTT table.
164 */
165 if ((GTT_HANDLE(master_softc) != MMIO_HANDLE(master_softc)) &&
166 (GTT_HANDLE(master_softc) != NULL))
167 ddi_regs_map_free(>T_HANDLE(master_softc));
168 if (MMIO_HANDLE(master_softc) != NULL)
169 ddi_regs_map_free(&MMIO_HANDLE(master_softc));
170 }
171
172 kmem_free(master_softc, sizeof (agp_master_softc_t));
173 master_softc = NULL;
174
175 return;
176
177 }
178
179 /*
180 * 965 has a fixed GTT table size (512KB), so check to see the actual aperture
181 * size. Aperture size = GTT table size * 1024.
182 */
183 static off_t
i965_apersize(agp_master_softc_t * agpmaster)184 i965_apersize(agp_master_softc_t *agpmaster)
185 {
186 off_t apersize;
187
188 apersize = AGPM_READ(agpmaster, PGTBL_CTL);
189 AGPM_DEBUG((CE_NOTE, "i965_apersize: PGTBL_CTL = %lx", apersize));
190 switch (apersize & GTT_SIZE_MASK) {
191 case GTT_2MB:
192 apersize = 2048;
193 break;
194 case GTT_1_5MB:
195 apersize = 1536;
196 break;
197 case GTT_1MB:
198 apersize = 1024;
199 break;
200 case GTT_512KB:
201 apersize = 512;
202 break;
203 case GTT_256KB:
204 apersize = 256;
205 break;
206 case GTT_128KB:
207 apersize = 128;
208 break;
209 default:
210 apersize = 0;
211 AGPM_DEBUG((CE_WARN,
212 "i965_apersize: invalid GTT size in PGTBL_CTL"));
213 }
214 return (apersize);
215 }
216
217 /*
218 * For Intel 3 series, we need to get GTT size from the GGMS field in GMCH
219 * Graphics Control Register. Return aperture size in MB.
220 */
221 static off_t
i3XX_apersize(ddi_acc_handle_t pci_acc_hdl)222 i3XX_apersize(ddi_acc_handle_t pci_acc_hdl)
223 {
224 uint16_t value;
225 off_t apersize;
226
227 /*
228 * Get the value of configuration register MGGC "Mirror of Dev0 GMCH
229 * Graphics Control" from Internal Graphics #2 (Device2:Function0).
230 */
231 value = pci_config_get16(pci_acc_hdl, I8XX_CONF_GC);
232 AGPM_DEBUG((CE_NOTE, "i3XX_apersize: MGGC = 0x%x", value));
233 /* computing aperture size using the pre-allocated GTT size */
234 switch (value & IX33_GGMS_MASK) {
235 case IX33_GGMS_1M:
236 apersize = 1024;
237 break;
238 case IX33_GGMS_2M:
239 apersize = 2048;
240 break;
241 default:
242 apersize = 0; /* no memory pre-allocated */
243 AGPM_DEBUG((CE_WARN,
244 "i3XX_apersize: no memory allocated for GTT"));
245 }
246 AGPM_DEBUG((CE_NOTE, "i3xx_apersize: apersize = %ldM", apersize));
247 return (apersize);
248 }
249
250 #define CHECK_STATUS(status) \
251 if (status != DDI_SUCCESS) { \
252 AGPM_DEBUG((CE_WARN, \
253 "set_gtt_mmio: regs_map_setup error")); \
254 return (-1); \
255 }
256 /*
257 * Set gtt_addr, gtt_mmio_base, igd_apersize, igd_aperbase and igd_devid
258 * according to chipset.
259 */
260 static int
set_gtt_mmio(dev_info_t * devi,agp_master_softc_t * agpmaster,ddi_acc_handle_t pci_acc_hdl)261 set_gtt_mmio(dev_info_t *devi, agp_master_softc_t *agpmaster,
262 ddi_acc_handle_t pci_acc_hdl)
263 {
264 off_t apersize; /* size of graphics mem (MB) == GTT size (KB) */
265 uint32_t value;
266 off_t gmadr_off; /* GMADR offset in PCI config space */
267 int status;
268
269 if (IS_INTEL_X33(agpmaster->agpm_id)) {
270 /* Intel 3 series are similar with 915/945 series */
271 status = ddi_regs_map_setup(devi, I915_GTTADDR,
272 >T_ADDR(agpmaster), 0, 0, &i8xx_dev_access,
273 >T_HANDLE(agpmaster));
274 CHECK_STATUS(status);
275
276 status = ddi_regs_map_setup(devi, I915_MMADR,
277 &MMIO_BASE(agpmaster), 0, 0, &i8xx_dev_access,
278 &MMIO_HANDLE(agpmaster));
279 CHECK_STATUS(status);
280
281 gmadr_off = I915_CONF_GMADR;
282 /* Different computing method used in getting aperture size. */
283 apersize = i3XX_apersize(pci_acc_hdl);
284 } else if (IS_INTEL_965(agpmaster->agpm_id)) {
285 status = ddi_regs_map_setup(devi, I965_GTTMMADR,
286 &MMIO_BASE(agpmaster), 0, 0, &i8xx_dev_access,
287 &MMIO_HANDLE(agpmaster));
288 CHECK_STATUS(status);
289 if ((agpmaster->agpm_id == INTEL_IGD_GM45) ||
290 IS_INTEL_G4X(agpmaster->agpm_id))
291 GTT_ADDR(agpmaster) =
292 MMIO_BASE(agpmaster) + GM45_GTT_OFFSET;
293 else
294 GTT_ADDR(agpmaster) =
295 MMIO_BASE(agpmaster) + I965_GTT_OFFSET;
296 GTT_HANDLE(agpmaster) = MMIO_HANDLE(agpmaster);
297
298 gmadr_off = I915_CONF_GMADR;
299 apersize = i965_apersize(agpmaster);
300 } else if (IS_INTEL_915(agpmaster->agpm_id)) {
301 /* I915/945 series */
302 status = ddi_regs_map_setup(devi, I915_GTTADDR,
303 >T_ADDR(agpmaster), 0, 0, &i8xx_dev_access,
304 >T_HANDLE(agpmaster));
305 CHECK_STATUS(status);
306
307 status = ddi_regs_map_setup(devi, I915_MMADR,
308 &MMIO_BASE(agpmaster), 0, 0, &i8xx_dev_access,
309 &MMIO_HANDLE(agpmaster));
310 CHECK_STATUS(status);
311
312 gmadr_off = I915_CONF_GMADR;
313 status = ddi_dev_regsize(devi, I915_GMADR, &apersize);
314 apersize = BYTES2MB(apersize);
315 } else {
316 /* I8XX series */
317 status = ddi_regs_map_setup(devi, I8XX_MMIO_BAR,
318 &MMIO_BASE(agpmaster), 0, 0, &i8xx_dev_access,
319 &MMIO_HANDLE(agpmaster));
320 CHECK_STATUS(status);
321
322 GTT_ADDR(agpmaster) = MMIO_BASE(agpmaster) + I8XX_PTE_OFFSET;
323 GTT_HANDLE(agpmaster) = MMIO_HANDLE(agpmaster);
324 gmadr_off = I8XX_CONF_GMADR;
325 status = ddi_dev_regsize(devi, I8XX_FB_BAR, &apersize);
326 apersize = BYTES2MB(apersize);
327 CHECK_STATUS(status);
328 }
329
330 /*
331 * If memory size is smaller than a certain value, it means
332 * the register set number for graphics memory range might
333 * be wrong
334 */
335 if (status != DDI_SUCCESS || apersize < 4) {
336 AGPM_DEBUG((CE_WARN,
337 "set_gtt_mmio: error in getting graphics memory"));
338 return (-1);
339 }
340
341 agpmaster->agpm_data.agpm_gtt.gtt_info.igd_apersize = apersize;
342
343 /* get graphics memory base address from GMADR */
344 value = pci_config_get32(pci_acc_hdl, gmadr_off);
345 APER_BASE(agpmaster) = value & GTT_BASE_MASK;
346 AGPM_DEBUG((CE_NOTE, "set_gtt_mmio: aperbase = 0x%x, apersize = %ldM, "
347 "gtt_addr = %p, mmio_base = %p", APER_BASE(agpmaster), apersize,
348 (void *)GTT_ADDR(agpmaster), (void *)MMIO_BASE(agpmaster)));
349 return (0);
350 }
351
352 /*
353 * Try to initialize agp master.
354 * 0 is returned if the device is successfully initialized. AGP master soft
355 * state is returned in master_softcp if needed.
356 * Otherwise -1 is returned and *master_softcp is set to NULL.
357 */
358 int
agpmaster_attach(dev_info_t * devi,agp_master_softc_t ** master_softcp,ddi_acc_handle_t pci_acc_hdl,minor_t minor)359 agpmaster_attach(dev_info_t *devi, agp_master_softc_t **master_softcp,
360 ddi_acc_handle_t pci_acc_hdl, minor_t minor)
361 {
362 int instance;
363 int status;
364 agp_master_softc_t *agpmaster;
365 char buf[80];
366
367
368 ASSERT(pci_acc_hdl);
369 *master_softcp = NULL;
370 agpmaster = (agp_master_softc_t *)
371 kmem_zalloc(sizeof (agp_master_softc_t), KM_SLEEP);
372
373 agpmaster->agpm_id =
374 pci_config_get32(pci_acc_hdl, PCI_CONF_VENID);
375 agpmaster->agpm_acc_hdl = pci_acc_hdl;
376
377 if (!detect_i8xx_device(agpmaster)) {
378 /* Intel 8XX, 915, 945 and 965 series */
379 if (set_gtt_mmio(devi, agpmaster, pci_acc_hdl) != 0)
380 goto fail;
381 } else if (detect_agp_devcice(agpmaster, pci_acc_hdl)) {
382 /* non IGD or AGP devices, AMD64 gart */
383 AGPM_DEBUG((CE_WARN,
384 "agpmaster_attach: neither IGD or AGP devices exists"));
385 agpmaster_detach(&agpmaster);
386 return (0);
387 }
388
389 agpmaster->agpm_data.agpm_gtt.gtt_info.igd_devid =
390 agpmaster->agpm_id;
391
392 /* create minor node for IGD or AGP device */
393 instance = ddi_get_instance(devi);
394
395 (void) sprintf(buf, "%s%d", AGPMASTER_NAME, instance);
396 status = ddi_create_minor_node(devi, buf, S_IFCHR, minor,
397 DDI_NT_AGP_MASTER, 0);
398
399 if (status != DDI_SUCCESS) {
400 AGPM_DEBUG((CE_WARN,
401 "agpmaster_attach: create agpmaster node failed"));
402 goto fail;
403 }
404
405 *master_softcp = agpmaster;
406 return (0);
407 fail:
408 agpmaster_detach(&agpmaster);
409 return (-1);
410 }
411
412 /*
413 * Currently, it handles ioctl requests related with agp master device for
414 * layered driver (agpgart) only.
415 */
416 /*ARGSUSED*/
417 int
agpmaster_ioctl(dev_t dev,int cmd,intptr_t data,int mode,cred_t * cred,int * rval,agp_master_softc_t * softc)418 agpmaster_ioctl(dev_t dev, int cmd, intptr_t data, int mode, cred_t *cred,
419 int *rval, agp_master_softc_t *softc)
420 {
421 uint32_t base;
422 uint32_t addr;
423 igd_gtt_seg_t seg;
424 agp_info_t info;
425 uint32_t value;
426 off_t cap;
427 uint32_t command;
428 static char kernel_only[] =
429 "agpmaster_ioctl: %s is a kernel only ioctl";
430
431 CONFIRM(softc);
432
433 switch (cmd) {
434 case DEVICE_DETECT:
435 if (!(mode & FKIOCTL)) {
436 AGPM_DEBUG((CE_CONT, kernel_only, "DEVICE_DETECT"));
437 return (ENXIO);
438 }
439
440 if (ddi_copyout(&softc->agpm_dev_type,
441 (void *)data, sizeof (int), mode))
442 return (EFAULT);
443 break;
444
445 case AGP_MASTER_SETCMD:
446 if (!(mode & FKIOCTL)) {
447 AGPM_DEBUG((CE_CONT, kernel_only, "AGP_MASTER_SETCMD"));
448 return (ENXIO);
449 }
450
451 CONFIRM(softc->agpm_dev_type == DEVICE_IS_AGP);
452 CONFIRM(softc->agpm_data.agpm_acaptr);
453
454 if (ddi_copyin((void *)data, &command,
455 sizeof (uint32_t), mode))
456 return (EFAULT);
457
458 pci_config_put32(softc->agpm_acc_hdl,
459 softc->agpm_data.agpm_acaptr + AGP_CONF_COMMAND,
460 command);
461 break;
462
463 case AGP_MASTER_GETINFO:
464 if (!(mode & FKIOCTL)) {
465 AGPM_DEBUG((CE_CONT, kernel_only,
466 "AGP_MASTER_GETINFO"));
467 return (ENXIO);
468 }
469
470 CONFIRM(softc->agpm_dev_type == DEVICE_IS_AGP);
471 CONFIRM(softc->agpm_data.agpm_acaptr);
472
473 cap = softc->agpm_data.agpm_acaptr;
474 value = pci_config_get32(softc->agpm_acc_hdl, cap);
475 info.agpi_version.agpv_major = (uint16_t)((value >> 20) & 0xf);
476 info.agpi_version.agpv_minor = (uint16_t)((value >> 16) & 0xf);
477 info.agpi_devid = softc->agpm_id;
478 info.agpi_mode = pci_config_get32(
479 softc->agpm_acc_hdl, cap + AGP_CONF_STATUS);
480
481 if (ddi_copyout(&info, (void *)data,
482 sizeof (agp_info_t), mode))
483 return (EFAULT);
484 break;
485
486 case I810_SET_GTT_BASE:
487 if (!(mode & FKIOCTL)) {
488 AGPM_DEBUG((CE_CONT, kernel_only, "I810_SET_GTT_ADDR"));
489 return (ENXIO);
490 }
491
492 CONFIRM(softc->agpm_dev_type == DEVICE_IS_I810);
493
494 if (ddi_copyin((void *)data, &base, sizeof (uint32_t), mode))
495 return (EFAULT);
496
497 /* enables page table */
498 addr = (base & GTT_BASE_MASK) | GTT_TABLE_VALID;
499
500 AGPM_WRITE(softc, PGTBL_CTL, addr);
501 break;
502
503 case I8XX_GET_INFO:
504 if (!(mode & FKIOCTL)) {
505 AGPM_DEBUG((CE_CONT, kernel_only, "I8XX_GET_INFO"));
506 return (ENXIO);
507 }
508
509 CONFIRM(IS_IGD(softc));
510
511 if (ddi_copyout(&softc->agpm_data.agpm_gtt.gtt_info,
512 (void *)data, sizeof (igd_info_t), mode))
513 return (EFAULT);
514 break;
515
516 case I8XX_ADD2GTT:
517 if (!(mode & FKIOCTL)) {
518 AGPM_DEBUG((CE_CONT, kernel_only, "I8XX_ADD2GTT"));
519 return (ENXIO);
520 }
521
522 CONFIRM(IS_IGD(softc));
523
524 if (ddi_copyin((void *)data, &seg,
525 sizeof (igd_gtt_seg_t), mode))
526 return (EFAULT);
527
528 if (i8xx_add_to_gtt(&softc->agpm_data.agpm_gtt, seg))
529 return (EINVAL);
530 break;
531
532 case I8XX_REM_GTT:
533 if (!(mode & FKIOCTL)) {
534 AGPM_DEBUG((CE_CONT, kernel_only, "I8XX_REM_GTT"));
535 return (ENXIO);
536 }
537
538 CONFIRM(IS_IGD(softc));
539
540 if (ddi_copyin((void *)data, &seg,
541 sizeof (igd_gtt_seg_t), mode))
542 return (EFAULT);
543
544 i8xx_remove_from_gtt(&softc->agpm_data.agpm_gtt, seg);
545 break;
546
547 case I8XX_RW_GTT:
548 if (!(mode & FKIOCTL)) {
549 AGPM_DEBUG((CE_CONT, kernel_only, "I8XX_RW_GTT"));
550 return (ENXIO);
551 }
552
553 CONFIRM(IS_IGD(softc));
554
555 if (ddi_copyin((void *)data, &seg,
556 sizeof (igd_gtt_seg_t), mode))
557 return (EFAULT);
558
559 /*
560 * Read or write based on flags set in
561 * ioctl_agpgart_rw_gtt()
562 * Used to save/restore GTT state.
563 */
564 if (seg.igs_flags == 0) {
565 if (i8xx_read_gtt(&softc->agpm_data.agpm_gtt, seg))
566 return (EINVAL);
567 } else {
568 if (i8xx_write_gtt(&softc->agpm_data.agpm_gtt, seg))
569 return (EINVAL);
570 }
571 break;
572
573 case I8XX_UNCONFIG:
574 if (!(mode & FKIOCTL)) {
575 AGPM_DEBUG((CE_CONT, kernel_only, "I8XX_UNCONFIG"));
576 return (ENXIO);
577 }
578
579 CONFIRM(IS_IGD(softc));
580
581 if (softc->agpm_dev_type == DEVICE_IS_I810)
582 AGPM_WRITE(softc, PGTBL_CTL, 0);
583 /*
584 * may need to clear all gtt entries here for i830 series,
585 * but may not be necessary
586 */
587 break;
588 }
589 return (0);
590 }
591
592 /*
593 * If AGP cap pointer is successfully found, none-zero value is returned.
594 * Otherwise 0 is returned.
595 */
596 static off_t
agpmaster_cap_find(ddi_acc_handle_t acc_handle)597 agpmaster_cap_find(ddi_acc_handle_t acc_handle)
598 {
599 off_t nextcap;
600 uint32_t ncapid;
601 uint8_t value;
602
603 /* check if this device supports capibility pointer */
604 value = (uint8_t)(pci_config_get16(acc_handle, PCI_CONF_STAT)
605 & PCI_CONF_CAP_MASK);
606
607 if (!value)
608 return (0);
609 /* get the offset of the first capability pointer from CAPPTR */
610 nextcap = (off_t)(pci_config_get8(acc_handle, AGP_CONF_CAPPTR));
611
612 /* check AGP capability from the first capability pointer */
613 while (nextcap) {
614 ncapid = pci_config_get32(acc_handle, nextcap);
615 if ((ncapid & PCI_CONF_CAPID_MASK)
616 == AGP_CAP_ID) /* find AGP cap */
617 break;
618
619 nextcap = (off_t)((ncapid & PCI_CONF_NCAPID_MASK) >> 8);
620 }
621
622 return (nextcap);
623
624 }
625
626 /*
627 * If i8xx device is successfully detected, 0 is returned.
628 * Otherwise -1 is returned.
629 */
630 static int
detect_i8xx_device(agp_master_softc_t * master_softc)631 detect_i8xx_device(agp_master_softc_t *master_softc)
632 {
633
634 switch (master_softc->agpm_id) {
635 case INTEL_IGD_810:
636 case INTEL_IGD_810DC:
637 case INTEL_IGD_810E:
638 case INTEL_IGD_815:
639 master_softc->agpm_dev_type = DEVICE_IS_I810;
640 break;
641 case INTEL_IGD_830M:
642 case INTEL_IGD_845G:
643 case INTEL_IGD_855GM:
644 case INTEL_IGD_865G:
645 case INTEL_IGD_915:
646 case INTEL_IGD_915GM:
647 case INTEL_IGD_945:
648 case INTEL_IGD_945GM:
649 case INTEL_IGD_945GME:
650 case INTEL_IGD_946GZ:
651 case INTEL_IGD_965G1:
652 case INTEL_IGD_965G2:
653 case INTEL_IGD_965GM:
654 case INTEL_IGD_965GME:
655 case INTEL_IGD_965Q:
656 case INTEL_IGD_Q35:
657 case INTEL_IGD_G33:
658 case INTEL_IGD_Q33:
659 case INTEL_IGD_GM45:
660 case INTEL_IGD_EL:
661 case INTEL_IGD_Q45:
662 case INTEL_IGD_G45:
663 case INTEL_IGD_G41:
664 case INTEL_IGD_IGDNG_D:
665 case INTEL_IGD_IGDNG_M:
666 case INTEL_IGD_B43:
667 /*
668 * Note: This module is not used for Intel Gen6 or later
669 * devices (Sandy Bridge etc.) so no need to add any
670 * PCI IDs here for those devices.
671 */
672 master_softc->agpm_dev_type = DEVICE_IS_I830;
673 break;
674 default: /* unknown id */
675 AGPM_DEBUG((CE_CONT, "unknown i8xx_device 0x%x",
676 master_softc->agpm_id));
677 return (-1);
678 }
679
680 return (0);
681 }
682
683 /*
684 * If agp master is successfully detected, 0 is returned.
685 * Otherwise -1 is returned.
686 */
687 static int
detect_agp_devcice(agp_master_softc_t * master_softc,ddi_acc_handle_t acc_handle)688 detect_agp_devcice(agp_master_softc_t *master_softc,
689 ddi_acc_handle_t acc_handle)
690 {
691 off_t cap;
692
693 cap = agpmaster_cap_find(acc_handle);
694 if (cap) {
695 master_softc->agpm_dev_type = DEVICE_IS_AGP;
696 master_softc->agpm_data.agpm_acaptr = cap;
697 return (0);
698 } else {
699 return (-1);
700 }
701
702 }
703
704 /*
705 * Please refer to GART and GTT entry format table in agpdefs.h for
706 * intel GTT entry format.
707 */
708 static int
phys2entry(uint32_t type,uint32_t physaddr,uint32_t * entry)709 phys2entry(uint32_t type, uint32_t physaddr, uint32_t *entry)
710 {
711 uint32_t value;
712
713 switch (type) {
714 case AGP_PHYSICAL:
715 case AGP_NORMAL:
716 value = (physaddr & GTT_PTE_MASK) | GTT_PTE_VALID;
717 break;
718 default:
719 AGPM_DEBUG((CE_WARN, "phys2entry type %d", type));
720 return (-1);
721 }
722
723 *entry = value;
724
725 return (0);
726 }
727
728 static int
i8xx_add_to_gtt(gtt_impl_t * gtt,igd_gtt_seg_t seg)729 i8xx_add_to_gtt(gtt_impl_t *gtt, igd_gtt_seg_t seg)
730 {
731 int i;
732 uint32_t *paddr;
733 uint32_t entry;
734 uint32_t maxpages;
735
736 maxpages = gtt->gtt_info.igd_apersize;
737 maxpages = GTT_MB_TO_PAGES(maxpages);
738
739 /* check if gtt max page number is reached */
740 if ((seg.igs_pgstart + seg.igs_npage) > maxpages)
741 return (-1);
742
743 /*
744 * Note: Caller supplies a gtt address from which we
745 * extract a uint32_t gtt_pte_t to set in the GTT.
746 */
747 paddr = seg.igs_phyaddr;
748 for (i = seg.igs_pgstart; i < (seg.igs_pgstart + seg.igs_npage);
749 i++, paddr++) {
750 if (phys2entry(seg.igs_type, *paddr, &entry))
751 return (-1);
752 ddi_put32(gtt->gtt_handle,
753 (uint32_t *)(gtt->gtt_addr + i * sizeof (uint32_t)),
754 entry);
755 }
756
757 return (0);
758 }
759
760 static void
i8xx_remove_from_gtt(gtt_impl_t * gtt,igd_gtt_seg_t seg)761 i8xx_remove_from_gtt(gtt_impl_t *gtt, igd_gtt_seg_t seg)
762 {
763 int i;
764 uint32_t maxpages;
765 uint32_t entry;
766
767 maxpages = gtt->gtt_info.igd_apersize;
768 maxpages = GTT_MB_TO_PAGES(maxpages);
769
770 /*
771 * If non-zero, seg.igs_scratch is the pfn_t for a
772 * "scratch" page to use instead of zero.
773 */
774 if (seg.igs_scratch == 0 ||
775 phys2entry(seg.igs_type, seg.igs_scratch, &entry) != 0) {
776 entry = 0;
777 }
778
779 /* check if gtt max page number is reached */
780 if ((seg.igs_pgstart + seg.igs_npage) > maxpages)
781 return;
782
783 for (i = seg.igs_pgstart; i < (seg.igs_pgstart + seg.igs_npage); i++) {
784 ddi_put32(gtt->gtt_handle,
785 (uint32_t *)(gtt->gtt_addr + i * sizeof (uint32_t)),
786 entry);
787 }
788 }
789
790 /*
791 * Low-level read GTT
792 */
793 static int
i8xx_read_gtt(gtt_impl_t * gtt,igd_gtt_seg_t seg)794 i8xx_read_gtt(gtt_impl_t *gtt, igd_gtt_seg_t seg)
795 {
796 int i;
797 uint32_t *paddr;
798 uint32_t maxpages;
799
800 maxpages = gtt->gtt_info.igd_apersize;
801 maxpages = GTT_MB_TO_PAGES(maxpages);
802
803 /* Buffer into which we'll read. */
804 paddr = seg.igs_phyaddr;
805 if (paddr == NULL)
806 return (-1);
807
808 /* check if gtt max page number is reached */
809 if ((seg.igs_pgstart + seg.igs_npage) > maxpages)
810 return (-1);
811
812 paddr = seg.igs_phyaddr;
813 for (i = seg.igs_pgstart; i < (seg.igs_pgstart + seg.igs_npage);
814 i++, paddr++) {
815 *paddr = ddi_get32(gtt->gtt_handle,
816 (uint32_t *)(gtt->gtt_addr + i * sizeof (uint32_t)));
817 }
818
819 return (0);
820 }
821
822 /*
823 * Low-level write GTT
824 */
825 static int
i8xx_write_gtt(gtt_impl_t * gtt,igd_gtt_seg_t seg)826 i8xx_write_gtt(gtt_impl_t *gtt, igd_gtt_seg_t seg)
827 {
828 int i;
829 uint32_t *paddr;
830 uint32_t maxpages;
831
832 maxpages = gtt->gtt_info.igd_apersize;
833 maxpages = GTT_MB_TO_PAGES(maxpages);
834
835 /* Buffer from which we'll write. */
836 paddr = seg.igs_phyaddr;
837 if (paddr == NULL)
838 return (-1);
839
840 /* check if gtt max page number is reached */
841 if ((seg.igs_pgstart + seg.igs_npage) > maxpages)
842 return (-1);
843
844 paddr = seg.igs_phyaddr;
845 for (i = seg.igs_pgstart; i < (seg.igs_pgstart + seg.igs_npage);
846 i++, paddr++) {
847 ddi_put32(gtt->gtt_handle,
848 (uint32_t *)(gtt->gtt_addr + i * sizeof (uint32_t)),
849 *paddr);
850 }
851
852 return (0);
853 }
854