1*1de22cf5Sriastradh /* $NetBSD: intel_gtt_subr.c,v 1.3 2021/12/19 12:37:36 riastradh Exp $ */
243f68184Sriastradh
343f68184Sriastradh /*-
443f68184Sriastradh * Copyright (c) 2014 The NetBSD Foundation, Inc.
543f68184Sriastradh * All rights reserved.
643f68184Sriastradh *
743f68184Sriastradh * This code is derived from software contributed to The NetBSD Foundation
843f68184Sriastradh * by Taylor R. Campbell.
943f68184Sriastradh *
1043f68184Sriastradh * Redistribution and use in source and binary forms, with or without
1143f68184Sriastradh * modification, are permitted provided that the following conditions
1243f68184Sriastradh * are met:
1343f68184Sriastradh * 1. Redistributions of source code must retain the above copyright
1443f68184Sriastradh * notice, this list of conditions and the following disclaimer.
1543f68184Sriastradh * 2. Redistributions in binary form must reproduce the above copyright
1643f68184Sriastradh * notice, this list of conditions and the following disclaimer in the
1743f68184Sriastradh * documentation and/or other materials provided with the distribution.
1843f68184Sriastradh *
1943f68184Sriastradh * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
2043f68184Sriastradh * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
2143f68184Sriastradh * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
2243f68184Sriastradh * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
2343f68184Sriastradh * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
2443f68184Sriastradh * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
2543f68184Sriastradh * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
2643f68184Sriastradh * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
2743f68184Sriastradh * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
2843f68184Sriastradh * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
2943f68184Sriastradh * POSSIBILITY OF SUCH DAMAGE.
3043f68184Sriastradh */
3143f68184Sriastradh
3243f68184Sriastradh /* Intel GTT stubs */
3343f68184Sriastradh
3443f68184Sriastradh #include <sys/cdefs.h>
35*1de22cf5Sriastradh __KERNEL_RCSID(0, "$NetBSD: intel_gtt_subr.c,v 1.3 2021/12/19 12:37:36 riastradh Exp $");
3643f68184Sriastradh
3743f68184Sriastradh #include <sys/types.h>
3843f68184Sriastradh #include <sys/bus.h>
3943f68184Sriastradh #include <sys/errno.h>
4043f68184Sriastradh #include <sys/systm.h>
4143f68184Sriastradh
4243f68184Sriastradh #include <machine/vmparam.h>
4343f68184Sriastradh
4443f68184Sriastradh #include <dev/pci/pcivar.h> /* XXX agpvar.h needs... */
4543f68184Sriastradh #include <dev/pci/agpvar.h>
4643f68184Sriastradh #include <dev/pci/agp_i810var.h>
4743f68184Sriastradh
48581f0a69Sriastradh #include <linux/pci.h>
4943f68184Sriastradh #include <linux/scatterlist.h>
5043f68184Sriastradh
51581f0a69Sriastradh #include "drm/i915_drm.h"
5243f68184Sriastradh #include "drm/intel-gtt.h"
5343f68184Sriastradh
54581f0a69Sriastradh static uint8_t
pci_conf_read8(pci_chipset_tag_t pc,pcitag_t tag,bus_size_t reg)55581f0a69Sriastradh pci_conf_read8(pci_chipset_tag_t pc, pcitag_t tag, bus_size_t reg)
56581f0a69Sriastradh {
57581f0a69Sriastradh uint32_t v;
58581f0a69Sriastradh
59581f0a69Sriastradh v = pci_conf_read(pc, tag, reg & ~3);
60581f0a69Sriastradh
61581f0a69Sriastradh return 0xff & (v >> (8 * (reg & 3)));
62581f0a69Sriastradh }
63581f0a69Sriastradh
64581f0a69Sriastradh static uint8_t
pci_read8(pci_chipset_tag_t pc,int bus,int dev,int func,bus_size_t reg)65581f0a69Sriastradh pci_read8(pci_chipset_tag_t pc, int bus, int dev, int func, bus_size_t reg)
66581f0a69Sriastradh {
67581f0a69Sriastradh pcitag_t tag = pci_make_tag(pc, bus, dev, func);
68581f0a69Sriastradh
69581f0a69Sriastradh return pci_conf_read8(pc, tag, reg);
70581f0a69Sriastradh }
71581f0a69Sriastradh
72581f0a69Sriastradh static uint16_t
pci_conf_read16(pci_chipset_tag_t pc,pcitag_t tag,bus_size_t reg)73581f0a69Sriastradh pci_conf_read16(pci_chipset_tag_t pc, pcitag_t tag, bus_size_t reg)
74581f0a69Sriastradh {
75581f0a69Sriastradh uint32_t v;
76581f0a69Sriastradh
77581f0a69Sriastradh KASSERT((reg & 1) == 0);
78581f0a69Sriastradh
79581f0a69Sriastradh v = pci_conf_read(pc, tag, reg & ~2);
80581f0a69Sriastradh
81581f0a69Sriastradh return 0xffff & (v >> (8 * (reg & 2)));
82581f0a69Sriastradh }
83581f0a69Sriastradh
84581f0a69Sriastradh static uint16_t
pci_read16(pci_chipset_tag_t pc,int bus,int dev,int func,bus_size_t reg)85581f0a69Sriastradh pci_read16(pci_chipset_tag_t pc, int bus, int dev, int func, bus_size_t reg)
86581f0a69Sriastradh {
87581f0a69Sriastradh pcitag_t tag = pci_make_tag(pc, bus, dev, func);
88581f0a69Sriastradh
89581f0a69Sriastradh return pci_conf_read16(pc, tag, reg);
90581f0a69Sriastradh }
91581f0a69Sriastradh
9243f68184Sriastradh /* Access to this should be single-threaded. */
9343f68184Sriastradh static struct {
9443f68184Sriastradh bus_dma_segment_t scratch_seg;
9543f68184Sriastradh bus_dmamap_t scratch_map;
9643f68184Sriastradh } intel_gtt;
9743f68184Sriastradh
98581f0a69Sriastradh /* XXX This logic should be merged with agp_i810.c. */
9943f68184Sriastradh struct resource intel_graphics_stolen_res;
10043f68184Sriastradh
101581f0a69Sriastradh static bus_size_t
i830_tseg_size(pci_chipset_tag_t pc)102581f0a69Sriastradh i830_tseg_size(pci_chipset_tag_t pc)
103581f0a69Sriastradh {
104581f0a69Sriastradh uint8_t esmramc = pci_read8(pc, 0, 0, 0, I830_ESMRAMC);
105581f0a69Sriastradh
106581f0a69Sriastradh if ((esmramc & TSEG_ENABLE) == 0)
107581f0a69Sriastradh return 0;
108581f0a69Sriastradh
109581f0a69Sriastradh return (esmramc & I830_TSEG_SIZE_1M) ? 1024*1024 : 512*1024;
110581f0a69Sriastradh }
111581f0a69Sriastradh
112581f0a69Sriastradh static bus_size_t
i845_tseg_size(pci_chipset_tag_t pc)113581f0a69Sriastradh i845_tseg_size(pci_chipset_tag_t pc)
114581f0a69Sriastradh {
115581f0a69Sriastradh uint8_t esmramc = pci_read8(pc, 0, 0, 0, I845_ESMRAMC);
116581f0a69Sriastradh
117581f0a69Sriastradh if ((esmramc & TSEG_ENABLE) == 0)
118581f0a69Sriastradh return 0;
119581f0a69Sriastradh
120581f0a69Sriastradh switch (esmramc & I845_TSEG_SIZE_MASK) {
121581f0a69Sriastradh case I845_TSEG_SIZE_512K:
122581f0a69Sriastradh return 512*1024;
123581f0a69Sriastradh case I845_TSEG_SIZE_1M:
124581f0a69Sriastradh return 1024*1024;
125581f0a69Sriastradh default:
126581f0a69Sriastradh return 0;
127581f0a69Sriastradh }
128581f0a69Sriastradh }
129581f0a69Sriastradh
130581f0a69Sriastradh static bus_size_t
i85x_tseg_size(pci_chipset_tag_t pc)131581f0a69Sriastradh i85x_tseg_size(pci_chipset_tag_t pc)
132581f0a69Sriastradh {
133581f0a69Sriastradh uint8_t esmramc = pci_read8(pc, 0, 0, 0, I85X_ESMRAMC);
134581f0a69Sriastradh
135581f0a69Sriastradh if ((esmramc & TSEG_ENABLE) == 0)
136581f0a69Sriastradh return 0;
137581f0a69Sriastradh
138581f0a69Sriastradh return 1024*1024;
139581f0a69Sriastradh }
140581f0a69Sriastradh
141581f0a69Sriastradh static bus_size_t
i830_tom(pci_chipset_tag_t pc)142581f0a69Sriastradh i830_tom(pci_chipset_tag_t pc)
143581f0a69Sriastradh {
144581f0a69Sriastradh uint8_t drb3 = pci_read8(pc, 0, 0, 0, I830_DRB3);
145581f0a69Sriastradh
146581f0a69Sriastradh return (bus_size_t)32*1024*1024 * drb3;
147581f0a69Sriastradh }
148581f0a69Sriastradh
149581f0a69Sriastradh static bus_size_t
i85x_tom(pci_chipset_tag_t pc)150581f0a69Sriastradh i85x_tom(pci_chipset_tag_t pc)
151581f0a69Sriastradh {
152581f0a69Sriastradh uint8_t drb3 = pci_read8(pc, 0, 0, 1, I85X_DRB3);
153581f0a69Sriastradh
154581f0a69Sriastradh return (bus_size_t)32*1024*1024 * drb3;
155581f0a69Sriastradh }
156581f0a69Sriastradh
157581f0a69Sriastradh static bus_size_t
i830_stolen_size(pci_chipset_tag_t pc,pcitag_t tag)158581f0a69Sriastradh i830_stolen_size(pci_chipset_tag_t pc, pcitag_t tag)
159581f0a69Sriastradh {
160581f0a69Sriastradh uint16_t gmch_ctrl = pci_read16(pc, 0, 0, 0, I830_GMCH_CTRL);
161581f0a69Sriastradh
162581f0a69Sriastradh switch (gmch_ctrl & I830_GMCH_GMS_MASK) {
163581f0a69Sriastradh case I830_GMCH_GMS_STOLEN_512:
164581f0a69Sriastradh return 512*1024;
165581f0a69Sriastradh case I830_GMCH_GMS_STOLEN_1024:
166581f0a69Sriastradh return 1024*1024;
167581f0a69Sriastradh case I830_GMCH_GMS_STOLEN_8192:
168581f0a69Sriastradh return 8*1024*1024;
169581f0a69Sriastradh case I830_GMCH_GMS_LOCAL:
170581f0a69Sriastradh default:
171581f0a69Sriastradh aprint_error("%s: invalid gmch_ctrl 0x%04x\n", __func__,
172581f0a69Sriastradh gmch_ctrl);
173581f0a69Sriastradh return 0;
174581f0a69Sriastradh }
175581f0a69Sriastradh }
176581f0a69Sriastradh
177581f0a69Sriastradh static bus_size_t
gen3_stolen_size(pci_chipset_tag_t pc,pcitag_t tag)178581f0a69Sriastradh gen3_stolen_size(pci_chipset_tag_t pc, pcitag_t tag)
179581f0a69Sriastradh {
180581f0a69Sriastradh uint16_t gmch_ctrl = pci_read16(pc, 0, 0, 0, I830_GMCH_CTRL);
181581f0a69Sriastradh
182581f0a69Sriastradh switch (gmch_ctrl & I855_GMCH_GMS_MASK) {
183581f0a69Sriastradh case I855_GMCH_GMS_STOLEN_1M:
184581f0a69Sriastradh return 1024*1024;
185581f0a69Sriastradh case I855_GMCH_GMS_STOLEN_4M:
186581f0a69Sriastradh return 4*1024*1024;
187581f0a69Sriastradh case I855_GMCH_GMS_STOLEN_8M:
188581f0a69Sriastradh return 8*1024*1024;
189581f0a69Sriastradh case I855_GMCH_GMS_STOLEN_16M:
190581f0a69Sriastradh return 16*1024*1024;
191581f0a69Sriastradh case I855_GMCH_GMS_STOLEN_32M:
192581f0a69Sriastradh return 32*1024*1024;
193581f0a69Sriastradh case I915_GMCH_GMS_STOLEN_48M:
194581f0a69Sriastradh return 48*1024*1024;
195581f0a69Sriastradh case I915_GMCH_GMS_STOLEN_64M:
196581f0a69Sriastradh return 64*1024*1024;
197581f0a69Sriastradh case G33_GMCH_GMS_STOLEN_128M:
198581f0a69Sriastradh return 128*1024*1024;
199581f0a69Sriastradh case G33_GMCH_GMS_STOLEN_256M:
200581f0a69Sriastradh return 256*1024*1024;
201581f0a69Sriastradh case INTEL_GMCH_GMS_STOLEN_96M:
202581f0a69Sriastradh return 96*1024*1024;
203581f0a69Sriastradh case INTEL_GMCH_GMS_STOLEN_160M:
204581f0a69Sriastradh return 160*1024*1024;
205581f0a69Sriastradh case INTEL_GMCH_GMS_STOLEN_224M:
206581f0a69Sriastradh return 224*1024*1024;
207581f0a69Sriastradh case INTEL_GMCH_GMS_STOLEN_352M:
208581f0a69Sriastradh return 352*1024*1024;
209581f0a69Sriastradh default:
210581f0a69Sriastradh aprint_error("%s: invalid gmch_ctrl 0x%04x\n", __func__,
211581f0a69Sriastradh gmch_ctrl);
212581f0a69Sriastradh return 0;
213581f0a69Sriastradh }
214581f0a69Sriastradh }
215581f0a69Sriastradh
216581f0a69Sriastradh static bus_size_t
gen6_stolen_size(pci_chipset_tag_t pc,pcitag_t tag)217581f0a69Sriastradh gen6_stolen_size(pci_chipset_tag_t pc, pcitag_t tag)
218581f0a69Sriastradh {
219581f0a69Sriastradh uint16_t gmch_ctrl = pci_conf_read16(pc, tag, SNB_GMCH_CTRL);
220581f0a69Sriastradh uint16_t gms = (gmch_ctrl >> SNB_GMCH_GMS_SHIFT) & SNB_GMCH_GMS_MASK;
221581f0a69Sriastradh
222581f0a69Sriastradh return (bus_size_t)32*1024*1024 * gms;
223581f0a69Sriastradh }
224581f0a69Sriastradh
225581f0a69Sriastradh static bus_size_t
gen8_stolen_size(pci_chipset_tag_t pc,pcitag_t tag)226581f0a69Sriastradh gen8_stolen_size(pci_chipset_tag_t pc, pcitag_t tag)
227581f0a69Sriastradh {
228581f0a69Sriastradh uint16_t gmch_ctrl = pci_conf_read16(pc, tag, SNB_GMCH_CTRL);
229581f0a69Sriastradh uint16_t gms = (gmch_ctrl >> BDW_GMCH_GMS_SHIFT) & BDW_GMCH_GMS_MASK;
230581f0a69Sriastradh
231581f0a69Sriastradh return (bus_size_t)32*1024*1024 * gms;
232581f0a69Sriastradh }
233581f0a69Sriastradh
234581f0a69Sriastradh static bus_size_t
chv_stolen_size(pci_chipset_tag_t pc,pcitag_t tag)235581f0a69Sriastradh chv_stolen_size(pci_chipset_tag_t pc, pcitag_t tag)
236581f0a69Sriastradh {
237581f0a69Sriastradh uint16_t gmch_ctrl = pci_conf_read16(pc, tag, SNB_GMCH_CTRL);
238581f0a69Sriastradh uint16_t gms = (gmch_ctrl >> SNB_GMCH_GMS_SHIFT) & SNB_GMCH_GMS_MASK;
239581f0a69Sriastradh
240581f0a69Sriastradh if (gms <= 0x10)
241581f0a69Sriastradh return (bus_size_t)32*1024*1024 * gms;
242581f0a69Sriastradh else if (gms <= 0x16)
243581f0a69Sriastradh return (bus_size_t)(8 + 4*(gms - 0x11))*1024*1024;
244581f0a69Sriastradh else
245581f0a69Sriastradh return (bus_size_t)(36 + 4*(gms - 0x17))*1024*1024;
246581f0a69Sriastradh }
247581f0a69Sriastradh
248581f0a69Sriastradh static bus_size_t
gen9_stolen_size(pci_chipset_tag_t pc,pcitag_t tag)249581f0a69Sriastradh gen9_stolen_size(pci_chipset_tag_t pc, pcitag_t tag)
250581f0a69Sriastradh {
251581f0a69Sriastradh uint16_t gmch_ctrl = pci_conf_read16(pc, tag, SNB_GMCH_CTRL);
252581f0a69Sriastradh uint16_t gms = (gmch_ctrl >> BDW_GMCH_GMS_SHIFT) & BDW_GMCH_GMS_MASK;
253581f0a69Sriastradh
254581f0a69Sriastradh if (gms <= 0xef)
255581f0a69Sriastradh return (bus_size_t)32*1024*1024 * gms;
256581f0a69Sriastradh else
257581f0a69Sriastradh return (bus_size_t)(4 + 4*(gms - 0xf0))*1024*1024;
258581f0a69Sriastradh }
259581f0a69Sriastradh
260581f0a69Sriastradh static bus_addr_t
i830_stolen_base(pci_chipset_tag_t pc,pcitag_t tag,bus_size_t stolen_size)261581f0a69Sriastradh i830_stolen_base(pci_chipset_tag_t pc, pcitag_t tag, bus_size_t stolen_size)
262581f0a69Sriastradh {
263581f0a69Sriastradh
264581f0a69Sriastradh return i830_tom(pc) - i830_tseg_size(pc) - stolen_size;
265581f0a69Sriastradh }
266581f0a69Sriastradh
267581f0a69Sriastradh static bus_addr_t
i845_stolen_base(pci_chipset_tag_t pc,pcitag_t tag,bus_size_t stolen_size)268581f0a69Sriastradh i845_stolen_base(pci_chipset_tag_t pc, pcitag_t tag, bus_size_t stolen_size)
269581f0a69Sriastradh {
270581f0a69Sriastradh
271581f0a69Sriastradh return i830_tom(pc) - i845_tseg_size(pc) - stolen_size;
272581f0a69Sriastradh }
273581f0a69Sriastradh
274581f0a69Sriastradh static bus_addr_t
i85x_stolen_base(pci_chipset_tag_t pc,pcitag_t tag,bus_size_t stolen_size)275581f0a69Sriastradh i85x_stolen_base(pci_chipset_tag_t pc, pcitag_t tag, bus_size_t stolen_size)
276581f0a69Sriastradh {
277581f0a69Sriastradh
278581f0a69Sriastradh return i85x_tom(pc) - i85x_tseg_size(pc) - stolen_size;
279581f0a69Sriastradh }
280581f0a69Sriastradh
281581f0a69Sriastradh static bus_addr_t
i865_stolen_base(pci_chipset_tag_t pc,pcitag_t tag,bus_size_t stolen_size)282581f0a69Sriastradh i865_stolen_base(pci_chipset_tag_t pc, pcitag_t tag, bus_size_t stolen_size)
283581f0a69Sriastradh {
284581f0a69Sriastradh uint16_t toud = pci_read16(pc, 0, 0, 0, I865_TOUD);
285581f0a69Sriastradh
286581f0a69Sriastradh return i845_tseg_size(pc) + (64*1024 * toud);
287581f0a69Sriastradh }
288581f0a69Sriastradh
289581f0a69Sriastradh static bus_addr_t
gen3_stolen_base(pci_chipset_tag_t pc,pcitag_t tag,bus_size_t stolen_size)290581f0a69Sriastradh gen3_stolen_base(pci_chipset_tag_t pc, pcitag_t tag, bus_size_t stolen_size)
291581f0a69Sriastradh {
292581f0a69Sriastradh uint32_t bsm = pci_conf_read(pc, tag, INTEL_BSM);
293581f0a69Sriastradh
294581f0a69Sriastradh return bsm & INTEL_BSM_MASK;
295581f0a69Sriastradh }
296581f0a69Sriastradh
297581f0a69Sriastradh static bus_addr_t
gen11_stolen_base(pci_chipset_tag_t pc,pcitag_t tag,bus_size_t stolen_size)298581f0a69Sriastradh gen11_stolen_base(pci_chipset_tag_t pc, pcitag_t tag, bus_size_t stolen_size)
299581f0a69Sriastradh {
300581f0a69Sriastradh uint32_t bsm;
301581f0a69Sriastradh
302581f0a69Sriastradh bsm = pci_conf_read(pc, tag, INTEL_GEN11_BSM_DW0) & INTEL_BSM_MASK;
303581f0a69Sriastradh bsm |= (uint64_t)pci_conf_read(pc, tag, INTEL_GEN11_BSM_DW1) << 32;
304581f0a69Sriastradh
305581f0a69Sriastradh return bsm;
306581f0a69Sriastradh }
307581f0a69Sriastradh
308581f0a69Sriastradh struct intel_stolen_ops {
309581f0a69Sriastradh bus_size_t (*size)(pci_chipset_tag_t, pcitag_t);
310581f0a69Sriastradh bus_addr_t (*base)(pci_chipset_tag_t, pcitag_t, bus_size_t);
311581f0a69Sriastradh };
312581f0a69Sriastradh
313581f0a69Sriastradh static const struct intel_stolen_ops i830_stolen_ops = {
314581f0a69Sriastradh .size = i830_stolen_size,
315581f0a69Sriastradh .base = i830_stolen_base,
316581f0a69Sriastradh };
317581f0a69Sriastradh
318581f0a69Sriastradh static const struct intel_stolen_ops i845_stolen_ops = {
319581f0a69Sriastradh .size = i830_stolen_size,
320581f0a69Sriastradh .base = i845_stolen_base,
321581f0a69Sriastradh };
322581f0a69Sriastradh
323581f0a69Sriastradh static const struct intel_stolen_ops i85x_stolen_ops = {
324581f0a69Sriastradh .size = gen3_stolen_size,
325581f0a69Sriastradh .base = i85x_stolen_base,
326581f0a69Sriastradh };
327581f0a69Sriastradh
328581f0a69Sriastradh static const struct intel_stolen_ops i865_stolen_ops = {
329581f0a69Sriastradh .size = gen3_stolen_size,
330581f0a69Sriastradh .base = i865_stolen_base,
331581f0a69Sriastradh };
332581f0a69Sriastradh
333581f0a69Sriastradh static const struct intel_stolen_ops gen3_stolen_ops = {
334581f0a69Sriastradh .size = gen3_stolen_size,
335581f0a69Sriastradh .base = gen3_stolen_base,
336581f0a69Sriastradh };
337581f0a69Sriastradh
338581f0a69Sriastradh static const struct intel_stolen_ops gen6_stolen_ops = {
339581f0a69Sriastradh .size = gen6_stolen_size,
340581f0a69Sriastradh .base = gen3_stolen_base,
341581f0a69Sriastradh };
342581f0a69Sriastradh
343581f0a69Sriastradh static const struct intel_stolen_ops gen8_stolen_ops = {
344581f0a69Sriastradh .size = gen8_stolen_size,
345581f0a69Sriastradh .base = gen3_stolen_base,
346581f0a69Sriastradh };
347581f0a69Sriastradh
348581f0a69Sriastradh static const struct intel_stolen_ops gen9_stolen_ops = {
349581f0a69Sriastradh .size = gen9_stolen_size,
350581f0a69Sriastradh .base = gen3_stolen_base,
351581f0a69Sriastradh };
352581f0a69Sriastradh
353581f0a69Sriastradh static const struct intel_stolen_ops chv_stolen_ops = {
354581f0a69Sriastradh .size = chv_stolen_size,
355581f0a69Sriastradh .base = gen3_stolen_base,
356581f0a69Sriastradh };
357581f0a69Sriastradh
358581f0a69Sriastradh static const struct intel_stolen_ops gen11_stolen_ops = {
359581f0a69Sriastradh .size = gen9_stolen_size,
360581f0a69Sriastradh .base = gen11_stolen_base,
361581f0a69Sriastradh };
362581f0a69Sriastradh
363581f0a69Sriastradh static const struct pci_device_id intel_stolen_ids[] = {
364581f0a69Sriastradh INTEL_I830_IDS(&i830_stolen_ops),
365581f0a69Sriastradh INTEL_I845G_IDS(&i845_stolen_ops),
366581f0a69Sriastradh INTEL_I85X_IDS(&i85x_stolen_ops),
367581f0a69Sriastradh INTEL_I865G_IDS(&i865_stolen_ops),
368581f0a69Sriastradh INTEL_I915G_IDS(&gen3_stolen_ops),
369581f0a69Sriastradh INTEL_I915GM_IDS(&gen3_stolen_ops),
370581f0a69Sriastradh INTEL_I945G_IDS(&gen3_stolen_ops),
371581f0a69Sriastradh INTEL_I945GM_IDS(&gen3_stolen_ops),
372581f0a69Sriastradh INTEL_VLV_IDS(&gen6_stolen_ops),
373581f0a69Sriastradh INTEL_PINEVIEW_G_IDS(&gen3_stolen_ops),
374581f0a69Sriastradh INTEL_PINEVIEW_M_IDS(&gen3_stolen_ops),
375581f0a69Sriastradh INTEL_I965G_IDS(&gen3_stolen_ops),
376581f0a69Sriastradh INTEL_G33_IDS(&gen3_stolen_ops),
377581f0a69Sriastradh INTEL_I965GM_IDS(&gen3_stolen_ops),
378581f0a69Sriastradh INTEL_GM45_IDS(&gen3_stolen_ops),
379581f0a69Sriastradh INTEL_G45_IDS(&gen3_stolen_ops),
380581f0a69Sriastradh INTEL_IRONLAKE_D_IDS(&gen3_stolen_ops),
381581f0a69Sriastradh INTEL_IRONLAKE_M_IDS(&gen3_stolen_ops),
382581f0a69Sriastradh INTEL_SNB_D_IDS(&gen6_stolen_ops),
383581f0a69Sriastradh INTEL_SNB_M_IDS(&gen6_stolen_ops),
384581f0a69Sriastradh INTEL_IVB_M_IDS(&gen6_stolen_ops),
385581f0a69Sriastradh INTEL_IVB_D_IDS(&gen6_stolen_ops),
386581f0a69Sriastradh INTEL_HSW_IDS(&gen6_stolen_ops),
387581f0a69Sriastradh INTEL_BDW_IDS(&gen8_stolen_ops),
388581f0a69Sriastradh INTEL_CHV_IDS(&chv_stolen_ops),
389581f0a69Sriastradh INTEL_SKL_IDS(&gen9_stolen_ops),
390581f0a69Sriastradh INTEL_BXT_IDS(&gen9_stolen_ops),
391581f0a69Sriastradh INTEL_KBL_IDS(&gen9_stolen_ops),
392581f0a69Sriastradh INTEL_CFL_IDS(&gen9_stolen_ops),
393581f0a69Sriastradh INTEL_GLK_IDS(&gen9_stolen_ops),
394581f0a69Sriastradh INTEL_CNL_IDS(&gen9_stolen_ops),
395581f0a69Sriastradh INTEL_ICL_11_IDS(&gen11_stolen_ops),
396581f0a69Sriastradh INTEL_EHL_IDS(&gen11_stolen_ops),
397581f0a69Sriastradh INTEL_TGL_12_IDS(&gen11_stolen_ops),
398581f0a69Sriastradh };
399581f0a69Sriastradh
40043f68184Sriastradh void
intel_gtt_get(uint64_t * va_size,bus_addr_t * aper_base,resource_size_t * aper_size)401*1de22cf5Sriastradh intel_gtt_get(uint64_t *va_size, bus_addr_t *aper_base,
402*1de22cf5Sriastradh resource_size_t *aper_size)
40343f68184Sriastradh {
404581f0a69Sriastradh struct agp_softc *sc;
405581f0a69Sriastradh pci_chipset_tag_t pc;
406581f0a69Sriastradh pcitag_t tag;
407581f0a69Sriastradh struct agp_i810_softc *isc;
408581f0a69Sriastradh const struct intel_stolen_ops *ops;
409581f0a69Sriastradh bus_addr_t stolen_base;
410581f0a69Sriastradh bus_size_t stolen_size;
411581f0a69Sriastradh unsigned i;
41243f68184Sriastradh
413581f0a69Sriastradh if ((sc = agp_i810_sc) == NULL) {
41443f68184Sriastradh *va_size = 0;
41543f68184Sriastradh *aper_base = 0;
41643f68184Sriastradh *aper_size = 0;
41743f68184Sriastradh return;
41843f68184Sriastradh }
41943f68184Sriastradh
420581f0a69Sriastradh pc = sc->as_pc;
421581f0a69Sriastradh tag = sc->as_tag;
422581f0a69Sriastradh
423581f0a69Sriastradh isc = sc->as_chipc;
42443f68184Sriastradh *va_size = ((size_t)(isc->gtt_size/sizeof(uint32_t)) << PAGE_SHIFT);
42543f68184Sriastradh *aper_base = sc->as_apaddr;
42643f68184Sriastradh *aper_size = sc->as_apsize;
42743f68184Sriastradh
428581f0a69Sriastradh for (i = 0; i < __arraycount(intel_stolen_ids); i++) {
429581f0a69Sriastradh if (intel_stolen_ids[i].device == PCI_PRODUCT(sc->as_id)) {
430581f0a69Sriastradh ops = (const struct intel_stolen_ops *)
431581f0a69Sriastradh intel_stolen_ids[i].driver_data;
432581f0a69Sriastradh stolen_size = (*ops->size)(pc, tag);
433581f0a69Sriastradh stolen_base = (*ops->base)(pc, tag, stolen_size);
434581f0a69Sriastradh intel_graphics_stolen_res.start = stolen_base;
435581f0a69Sriastradh intel_graphics_stolen_res.end =
436581f0a69Sriastradh stolen_base + stolen_size - 1;
437581f0a69Sriastradh break;
438581f0a69Sriastradh }
439581f0a69Sriastradh }
44043f68184Sriastradh }
44143f68184Sriastradh
44243f68184Sriastradh int
intel_gmch_probe(struct pci_dev * bridge_pci __unused,struct pci_dev * gpu __unused,struct agp_bridge_data * bridge_agp __unused)44343f68184Sriastradh intel_gmch_probe(struct pci_dev *bridge_pci __unused,
44443f68184Sriastradh struct pci_dev *gpu __unused, struct agp_bridge_data *bridge_agp __unused)
44543f68184Sriastradh {
44643f68184Sriastradh struct agp_softc *const sc = agp_i810_sc;
44743f68184Sriastradh int nsegs;
44843f68184Sriastradh int error;
44943f68184Sriastradh
45043f68184Sriastradh if (sc == NULL)
45143f68184Sriastradh return 0;
45243f68184Sriastradh
45343f68184Sriastradh error = bus_dmamem_alloc(sc->as_dmat, PAGE_SIZE, PAGE_SIZE, 0,
45443f68184Sriastradh &intel_gtt.scratch_seg, 1, &nsegs, BUS_DMA_WAITOK);
45543f68184Sriastradh if (error)
45643f68184Sriastradh goto fail0;
45743f68184Sriastradh KASSERT(nsegs == 1);
45843f68184Sriastradh
45943f68184Sriastradh error = bus_dmamap_create(sc->as_dmat, PAGE_SIZE, 1, PAGE_SIZE, 0,
46043f68184Sriastradh BUS_DMA_WAITOK, &intel_gtt.scratch_map);
46143f68184Sriastradh if (error)
46243f68184Sriastradh goto fail1;
46343f68184Sriastradh
46443f68184Sriastradh error = bus_dmamap_load_raw(sc->as_dmat, intel_gtt.scratch_map,
46543f68184Sriastradh &intel_gtt.scratch_seg, 1, PAGE_SIZE, BUS_DMA_WAITOK);
46643f68184Sriastradh if (error)
46743f68184Sriastradh goto fail2;
46843f68184Sriastradh
46943f68184Sriastradh /* Success! */
47043f68184Sriastradh return 1;
47143f68184Sriastradh
47243f68184Sriastradh fail3: __unused
47343f68184Sriastradh bus_dmamap_unload(sc->as_dmat, intel_gtt.scratch_map);
47443f68184Sriastradh fail2: bus_dmamap_destroy(sc->as_dmat, intel_gtt.scratch_map);
47543f68184Sriastradh fail1: bus_dmamem_free(sc->as_dmat, &intel_gtt.scratch_seg, 1);
47643f68184Sriastradh fail0: KASSERT(error);
47743f68184Sriastradh return 0;
47843f68184Sriastradh }
47943f68184Sriastradh
48043f68184Sriastradh void
intel_gmch_remove(void)48143f68184Sriastradh intel_gmch_remove(void)
48243f68184Sriastradh {
48343f68184Sriastradh struct agp_softc *const sc = agp_i810_sc;
48443f68184Sriastradh
48543f68184Sriastradh bus_dmamap_unload(sc->as_dmat, intel_gtt.scratch_map);
48643f68184Sriastradh bus_dmamap_destroy(sc->as_dmat, intel_gtt.scratch_map);
48743f68184Sriastradh bus_dmamem_free(sc->as_dmat, &intel_gtt.scratch_seg, 1);
48843f68184Sriastradh }
48943f68184Sriastradh
49043f68184Sriastradh bool
intel_enable_gtt(void)49143f68184Sriastradh intel_enable_gtt(void)
49243f68184Sriastradh {
49343f68184Sriastradh struct agp_softc *sc = agp_i810_sc;
49443f68184Sriastradh struct agp_i810_softc *isc;
49543f68184Sriastradh
49643f68184Sriastradh if (sc == NULL)
49743f68184Sriastradh return false;
49843f68184Sriastradh isc = sc->as_chipc;
49943f68184Sriastradh agp_i810_reset(isc);
50043f68184Sriastradh return true;
50143f68184Sriastradh }
50243f68184Sriastradh
50343f68184Sriastradh void
intel_gtt_chipset_flush(void)50443f68184Sriastradh intel_gtt_chipset_flush(void)
50543f68184Sriastradh {
50643f68184Sriastradh
50743f68184Sriastradh KASSERT(agp_i810_sc != NULL);
50843f68184Sriastradh agp_i810_chipset_flush(agp_i810_sc->as_chipc);
50943f68184Sriastradh }
51043f68184Sriastradh
51143f68184Sriastradh static int
intel_gtt_flags(unsigned flags)51243f68184Sriastradh intel_gtt_flags(unsigned flags)
51343f68184Sriastradh {
51443f68184Sriastradh int gtt_flags = AGP_I810_GTT_VALID;
51543f68184Sriastradh
51643f68184Sriastradh switch (flags) {
51743f68184Sriastradh case AGP_USER_MEMORY:
51843f68184Sriastradh break;
51943f68184Sriastradh case AGP_USER_CACHED_MEMORY:
52043f68184Sriastradh gtt_flags |= AGP_I810_GTT_CACHED;
52143f68184Sriastradh break;
52243f68184Sriastradh default:
52343f68184Sriastradh panic("invalid intel gtt flags: %x", flags);
52443f68184Sriastradh }
52543f68184Sriastradh
52643f68184Sriastradh return gtt_flags;
52743f68184Sriastradh }
52843f68184Sriastradh
52943f68184Sriastradh void
intel_gtt_insert_page(bus_addr_t addr,unsigned va_page,unsigned flags)53043f68184Sriastradh intel_gtt_insert_page(bus_addr_t addr, unsigned va_page, unsigned flags)
53143f68184Sriastradh {
53243f68184Sriastradh struct agp_i810_softc *const isc = agp_i810_sc->as_chipc;
53343f68184Sriastradh off_t va = (off_t)va_page << PAGE_SHIFT;
53443f68184Sriastradh int gtt_flags = intel_gtt_flags(flags);
53543f68184Sriastradh int error;
53643f68184Sriastradh
53743f68184Sriastradh error = agp_i810_write_gtt_entry(isc, va, addr, gtt_flags);
53843f68184Sriastradh if (error)
53943f68184Sriastradh device_printf(agp_i810_sc->as_dev,
54043f68184Sriastradh "write gtt entry"
54143f68184Sriastradh " %"PRIxMAX" -> %"PRIxMAX" (flags=%x) failed: %d\n",
54243f68184Sriastradh (uintmax_t)va, (uintmax_t)addr, flags,
54343f68184Sriastradh error);
54443f68184Sriastradh agp_i810_post_gtt_entry(isc, va);
54543f68184Sriastradh intel_gtt_chipset_flush();
54643f68184Sriastradh }
54743f68184Sriastradh
54843f68184Sriastradh void
intel_gtt_insert_sg_entries(struct sg_table * sg,unsigned va_page,unsigned flags)54943f68184Sriastradh intel_gtt_insert_sg_entries(struct sg_table *sg, unsigned va_page,
55043f68184Sriastradh unsigned flags)
55143f68184Sriastradh {
55243f68184Sriastradh bus_dmamap_t dmamap = sg->sgl[0].sg_dmamap;
55343f68184Sriastradh struct agp_i810_softc *const isc = agp_i810_sc->as_chipc;
55443f68184Sriastradh off_t va = (off_t)va_page << PAGE_SHIFT;
55543f68184Sriastradh unsigned seg;
55643f68184Sriastradh int gtt_flags = intel_gtt_flags(flags);
55743f68184Sriastradh int error;
55843f68184Sriastradh
55943f68184Sriastradh KASSERT(0 <= va);
56043f68184Sriastradh KASSERT((va >> PAGE_SHIFT) == va_page);
56143f68184Sriastradh KASSERT(0 < dmamap->dm_nsegs);
56243f68184Sriastradh
56343f68184Sriastradh for (seg = 0; seg < dmamap->dm_nsegs; seg++) {
56443f68184Sriastradh const bus_addr_t addr = dmamap->dm_segs[seg].ds_addr;
56543f68184Sriastradh bus_size_t len;
56643f68184Sriastradh
56743f68184Sriastradh for (len = dmamap->dm_segs[seg].ds_len;
56843f68184Sriastradh len >= PAGE_SIZE;
56943f68184Sriastradh len -= PAGE_SIZE, va += PAGE_SIZE) {
57043f68184Sriastradh error = agp_i810_write_gtt_entry(isc, va, addr,
57143f68184Sriastradh gtt_flags);
57243f68184Sriastradh if (error)
57343f68184Sriastradh device_printf(agp_i810_sc->as_dev,
57443f68184Sriastradh "write gtt entry"
57543f68184Sriastradh " %"PRIxMAX" -> %"PRIxMAX" (flags=%x)"
57643f68184Sriastradh " failed: %d\n",
57743f68184Sriastradh (uintmax_t)va, (uintmax_t)addr, flags,
57843f68184Sriastradh error);
57943f68184Sriastradh }
58043f68184Sriastradh KASSERTMSG(len == 0,
58143f68184Sriastradh "segment length not divisible by PAGE_SIZE: %jx",
58243f68184Sriastradh (uintmax_t)dmamap->dm_segs[seg].ds_len);
58343f68184Sriastradh }
58443f68184Sriastradh agp_i810_post_gtt_entry(isc, (va - PAGE_SIZE));
58543f68184Sriastradh intel_gtt_chipset_flush();
58643f68184Sriastradh }
58743f68184Sriastradh
58843f68184Sriastradh void
intel_gtt_clear_range(unsigned va_page,unsigned npages)58943f68184Sriastradh intel_gtt_clear_range(unsigned va_page, unsigned npages)
59043f68184Sriastradh {
59143f68184Sriastradh struct agp_i810_softc *const isc = agp_i810_sc->as_chipc;
59243f68184Sriastradh const bus_addr_t addr = intel_gtt.scratch_map->dm_segs[0].ds_addr;
59343f68184Sriastradh const int gtt_flags = AGP_I810_GTT_VALID;
59443f68184Sriastradh off_t va = (va_page << PAGE_SHIFT);
59543f68184Sriastradh
59643f68184Sriastradh KASSERT(0 <= va);
59743f68184Sriastradh KASSERT((va >> PAGE_SHIFT) == va_page);
59843f68184Sriastradh KASSERT(0 < npages);
59943f68184Sriastradh
60043f68184Sriastradh while (npages--) {
60143f68184Sriastradh agp_i810_write_gtt_entry(isc, va, addr, gtt_flags);
60243f68184Sriastradh va += PAGE_SIZE;
60343f68184Sriastradh }
60443f68184Sriastradh agp_i810_post_gtt_entry(isc, va - PAGE_SIZE);
60543f68184Sriastradh }
606