1/* $NetBSD: intel_gtt.c,v 1.5 2015/03/06 22:03:06 riastradh Exp $ */
2
3/*-
4 * Copyright (c) 2014 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Taylor R. Campbell.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
30 */
31
32/* Intel GTT stubs */
33
34#include <sys/cdefs.h>
35__KERNEL_RCSID(0, "$NetBSD: intel_gtt.c,v 1.5 2015/03/06 22:03:06 riastradh Exp $");
36
37#include <sys/types.h>
38#include <sys/bus.h>
39#include <sys/errno.h>
40#include <sys/systm.h>
41
42#include <machine/vmparam.h>
43
44#include <dev/pci/pcivar.h> /* XXX agpvar.h needs... */
45#include <dev/pci/agpvar.h>
46#include <dev/pci/agp_i810var.h>
47
48#include "drm/intel-gtt.h"
49
50/* Access to this should be single-threaded. */
51static struct {
52 bus_dma_segment_t scratch_seg;
53 bus_dmamap_t scratch_map;
54} intel_gtt;
55
56void
57intel_gtt_get(size_t *va_size, size_t *stolen_size, bus_addr_t *aper_base,
58 unsigned long *aper_size)
59{
60 struct agp_softc *const sc = agp_i810_sc;
61
62 if (sc == NULL) {
63 *va_size = 0;
64 *stolen_size = 0;
65 *aper_base = 0;
66 *aper_size = 0;
67 return;
68 }
69
70 struct agp_i810_softc *const isc = sc->as_chipc;
71 *va_size = ((size_t)(isc->gtt_size/sizeof(uint32_t)) << PAGE_SHIFT);
72 *stolen_size = ((size_t)isc->stolen << PAGE_SHIFT);
73 *aper_base = sc->as_apaddr;
74 *aper_size = sc->as_apsize;
75}
76
77int
78intel_gmch_probe(struct pci_dev *bridge_pci __unused,
79 struct pci_dev *gpu __unused, struct agp_bridge_data *bridge_agp __unused)
80{
81 struct agp_softc *const sc = agp_i810_sc;
82 int nsegs;
83 int error;
84
85 if (sc == NULL)
86 return 0;
87
88 error = bus_dmamem_alloc(sc->as_dmat, PAGE_SIZE, PAGE_SIZE, 0,
89 &intel_gtt.scratch_seg, 1, &nsegs, BUS_DMA_WAITOK);
90 if (error)
91 goto fail0;
92 KASSERT(nsegs == 1);
93
94 error = bus_dmamap_create(sc->as_dmat, PAGE_SIZE, 1, PAGE_SIZE, 0,
95 BUS_DMA_WAITOK, &intel_gtt.scratch_map);
96 if (error)
97 goto fail1;
98
99 error = bus_dmamap_load_raw(sc->as_dmat, intel_gtt.scratch_map,
100 &intel_gtt.scratch_seg, 1, PAGE_SIZE, BUS_DMA_WAITOK);
101 if (error)
102 goto fail2;
103
104 /* Success! */
105 return 1;
106
107fail3: __unused
108 bus_dmamap_unload(sc->as_dmat, intel_gtt.scratch_map);
109fail2: bus_dmamap_destroy(sc->as_dmat, intel_gtt.scratch_map);
110fail1: bus_dmamem_free(sc->as_dmat, &intel_gtt.scratch_seg, 1);
111fail0: KASSERT(error);
112 return 0;
113}
114
115void
116intel_gmch_remove(void)
117{
118 struct agp_softc *const sc = agp_i810_sc;
119
120 bus_dmamap_unload(sc->as_dmat, intel_gtt.scratch_map);
121 bus_dmamap_destroy(sc->as_dmat, intel_gtt.scratch_map);
122 bus_dmamem_free(sc->as_dmat, &intel_gtt.scratch_seg, 1);
123}
124
125bool
126intel_enable_gtt(void)
127{
128
129 return (agp_i810_sc != NULL);
130}
131
132void
133intel_gtt_chipset_flush(void)
134{
135
136 KASSERT(agp_i810_sc != NULL);
137 agp_i810_chipset_flush(agp_i810_sc->as_chipc);
138}
139
140void
141intel_gtt_insert_entries(bus_dmamap_t dmamap, unsigned va_page, unsigned flags)
142{
143 struct agp_i810_softc *const isc = agp_i810_sc->as_chipc;
144 off_t va = (va_page << PAGE_SHIFT);
145 unsigned seg;
146 int gtt_flags = 0;
147 int error;
148
149 KASSERT(0 <= va);
150 KASSERT((va >> PAGE_SHIFT) == va_page);
151 KASSERT(0 < dmamap->dm_nsegs);
152
153 gtt_flags |= AGP_I810_GTT_VALID;
154 switch (flags) {
155 case AGP_USER_MEMORY:
156 break;
157 case AGP_USER_CACHED_MEMORY:
158 gtt_flags |= AGP_I810_GTT_CACHED;
159 break;
160 default:
161 panic("invalid intel gtt flags: %x", flags);
162 }
163
164 for (seg = 0; seg < dmamap->dm_nsegs; seg++) {
165 const bus_addr_t addr = dmamap->dm_segs[seg].ds_addr;
166
167 KASSERT(dmamap->dm_segs[seg].ds_len == PAGE_SIZE);
168
169 /* XXX Respect flags. */
170 error = agp_i810_write_gtt_entry(isc, va, addr, gtt_flags);
171 if (error)
172 device_printf(agp_i810_sc->as_dev,
173 "write gtt entry"
174 " %"PRIxMAX" -> %"PRIxMAX" failed: %d\n",
175 (uintmax_t)va, (uintmax_t)(addr | 1), error);
176 va += PAGE_SIZE;
177 }
178 agp_i810_post_gtt_entry(isc, (va - PAGE_SIZE));
179}
180
181void
182intel_gtt_clear_range(unsigned va_page, unsigned npages)
183{
184 struct agp_i810_softc *const isc = agp_i810_sc->as_chipc;
185 const bus_addr_t addr = intel_gtt.scratch_map->dm_segs[0].ds_addr;
186 const int gtt_flags = AGP_I810_GTT_VALID;
187 off_t va = (va_page << PAGE_SHIFT);
188
189 KASSERT(0 <= va);
190 KASSERT((va >> PAGE_SHIFT) == va_page);
191 KASSERT(0 < npages);
192
193 while (npages--) {
194 agp_i810_write_gtt_entry(isc, va, addr, gtt_flags);
195 va += PAGE_SIZE;
196 }
197 agp_i810_post_gtt_entry(isc, va - PAGE_SIZE);
198}
199