1*6b5045cdSchristos /* $NetBSD: pci_ranges.c,v 1.9 2021/06/21 03:01:23 christos Exp $ */
2cfc495a0Sdyoung
3cfc495a0Sdyoung /*-
4cfc495a0Sdyoung * Copyright (c) 2011 The NetBSD Foundation, Inc.
5cfc495a0Sdyoung * All rights reserved.
6cfc495a0Sdyoung *
7cfc495a0Sdyoung * This code is derived from software contributed to The NetBSD Foundation
8cfc495a0Sdyoung * by David Young <dyoung@NetBSD.org>.
9cfc495a0Sdyoung *
10cfc495a0Sdyoung * Redistribution and use in source and binary forms, with or without
11cfc495a0Sdyoung * modification, are permitted provided that the following conditions
12cfc495a0Sdyoung * are met:
13cfc495a0Sdyoung * 1. Redistributions of source code must retain the above copyright
14cfc495a0Sdyoung * notice, this list of conditions and the following disclaimer.
15cfc495a0Sdyoung * 2. Redistributions in binary form must reproduce the above copyright
16cfc495a0Sdyoung * notice, this list of conditions and the following disclaimer in the
17cfc495a0Sdyoung * documentation and/or other materials provided with the distribution.
18cfc495a0Sdyoung *
19cfc495a0Sdyoung * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20cfc495a0Sdyoung * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21cfc495a0Sdyoung * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22cfc495a0Sdyoung * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23cfc495a0Sdyoung * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24cfc495a0Sdyoung * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25cfc495a0Sdyoung * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26cfc495a0Sdyoung * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27cfc495a0Sdyoung * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28cfc495a0Sdyoung * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29cfc495a0Sdyoung * POSSIBILITY OF SUCH DAMAGE.
30cfc495a0Sdyoung */
31cfc495a0Sdyoung
32cfc495a0Sdyoung
33cfc495a0Sdyoung #include <sys/cdefs.h>
34*6b5045cdSchristos __KERNEL_RCSID(0, "$NetBSD: pci_ranges.c,v 1.9 2021/06/21 03:01:23 christos Exp $");
35cfc495a0Sdyoung
36cfc495a0Sdyoung #include <sys/types.h>
37cfc495a0Sdyoung #include <sys/param.h>
38cfc495a0Sdyoung #include <sys/systm.h>
39cfc495a0Sdyoung #include <sys/errno.h>
40cfc495a0Sdyoung #include <sys/bus.h>
41cfc495a0Sdyoung #include <sys/kmem.h>
42cfc495a0Sdyoung
43cfc495a0Sdyoung #include <prop/proplib.h>
44cfc495a0Sdyoung #include <ppath/ppath.h>
45cfc495a0Sdyoung
46cfc495a0Sdyoung #include <dev/pci/pcivar.h>
47cfc495a0Sdyoung #include <dev/pci/pcireg.h>
48cfc495a0Sdyoung #include <dev/pci/pccbbreg.h>
49cfc495a0Sdyoung
508295eb1bSdyoung #include <machine/autoconf.h>
518295eb1bSdyoung
52cfc495a0Sdyoung typedef enum pci_alloc_regtype {
53cfc495a0Sdyoung PCI_ALLOC_REGTYPE_NONE = 0
54cfc495a0Sdyoung , PCI_ALLOC_REGTYPE_BAR = 1
55cfc495a0Sdyoung , PCI_ALLOC_REGTYPE_WIN = 2
56cfc495a0Sdyoung , PCI_ALLOC_REGTYPE_CBWIN = 3
57cfc495a0Sdyoung , PCI_ALLOC_REGTYPE_VGA_EN = 4
58cfc495a0Sdyoung } pci_alloc_regtype_t;
59cfc495a0Sdyoung
60cfc495a0Sdyoung typedef enum pci_alloc_space {
61cfc495a0Sdyoung PCI_ALLOC_SPACE_IO = 0
62cfc495a0Sdyoung , PCI_ALLOC_SPACE_MEM = 1
63cfc495a0Sdyoung } pci_alloc_space_t;
64cfc495a0Sdyoung
65cfc495a0Sdyoung typedef enum pci_alloc_flags {
66cfc495a0Sdyoung PCI_ALLOC_F_PREFETCHABLE = 0x1
67cfc495a0Sdyoung } pci_alloc_flags_t;
68cfc495a0Sdyoung
69cfc495a0Sdyoung typedef struct pci_alloc {
70cfc495a0Sdyoung TAILQ_ENTRY(pci_alloc) pal_link;
71cfc495a0Sdyoung pcitag_t pal_tag;
72cfc495a0Sdyoung uint64_t pal_addr;
73cfc495a0Sdyoung uint64_t pal_size;
74cfc495a0Sdyoung pci_alloc_regtype_t pal_type;
75cfc495a0Sdyoung struct pci_alloc_reg {
76cfc495a0Sdyoung int r_ofs;
77cfc495a0Sdyoung pcireg_t r_val;
78cfc495a0Sdyoung pcireg_t r_mask;
79cfc495a0Sdyoung } pal_reg[3];
80cfc495a0Sdyoung pci_alloc_space_t pal_space;
81cfc495a0Sdyoung pci_alloc_flags_t pal_flags;
82cfc495a0Sdyoung } pci_alloc_t;
83cfc495a0Sdyoung
84cfc495a0Sdyoung typedef struct pci_alloc_reg pci_alloc_reg_t;
85cfc495a0Sdyoung
86cfc495a0Sdyoung TAILQ_HEAD(pci_alloc_list, pci_alloc);
87cfc495a0Sdyoung
88cfc495a0Sdyoung typedef struct pci_alloc_list pci_alloc_list_t;
89cfc495a0Sdyoung
90cfc495a0Sdyoung static pci_alloc_t *
pci_alloc_dup(const pci_alloc_t * pal)91cfc495a0Sdyoung pci_alloc_dup(const pci_alloc_t *pal)
92cfc495a0Sdyoung {
93cfc495a0Sdyoung pci_alloc_t *npal;
94cfc495a0Sdyoung
95fd34ea77Schs npal = kmem_alloc(sizeof(*npal), KM_SLEEP);
96cfc495a0Sdyoung *npal = *pal;
97cfc495a0Sdyoung return npal;
98cfc495a0Sdyoung }
99cfc495a0Sdyoung
100cfc495a0Sdyoung static bool
pci_alloc_linkdup(pci_alloc_list_t * pals,const pci_alloc_t * pal)101cfc495a0Sdyoung pci_alloc_linkdup(pci_alloc_list_t *pals, const pci_alloc_t *pal)
102cfc495a0Sdyoung {
103cfc495a0Sdyoung pci_alloc_t *npal;
104cfc495a0Sdyoung
105cfc495a0Sdyoung if ((npal = pci_alloc_dup(pal)) == NULL)
106cfc495a0Sdyoung return false;
107cfc495a0Sdyoung
108cfc495a0Sdyoung TAILQ_INSERT_TAIL(pals, npal, pal_link);
109cfc495a0Sdyoung
110cfc495a0Sdyoung return true;
111cfc495a0Sdyoung }
112cfc495a0Sdyoung
113cfc495a0Sdyoung struct range_infer_ctx {
114cfc495a0Sdyoung pci_chipset_tag_t ric_pc;
115cfc495a0Sdyoung pci_alloc_list_t ric_pals;
116cfc495a0Sdyoung bus_addr_t ric_mmio_bottom;
117cfc495a0Sdyoung bus_addr_t ric_mmio_top;
118cfc495a0Sdyoung bus_addr_t ric_io_bottom;
119cfc495a0Sdyoung bus_addr_t ric_io_top;
120cfc495a0Sdyoung };
121cfc495a0Sdyoung
122cfc495a0Sdyoung static bool
io_range_extend(struct range_infer_ctx * ric,const pci_alloc_t * pal)123cfc495a0Sdyoung io_range_extend(struct range_infer_ctx *ric, const pci_alloc_t *pal)
124cfc495a0Sdyoung {
125cfc495a0Sdyoung if (ric->ric_io_bottom > pal->pal_addr)
126cfc495a0Sdyoung ric->ric_io_bottom = pal->pal_addr;
127cfc495a0Sdyoung if (ric->ric_io_top < pal->pal_addr + pal->pal_size)
128cfc495a0Sdyoung ric->ric_io_top = pal->pal_addr + pal->pal_size;
129cfc495a0Sdyoung
130cfc495a0Sdyoung return pci_alloc_linkdup(&ric->ric_pals, pal);
131cfc495a0Sdyoung }
132cfc495a0Sdyoung
133cfc495a0Sdyoung static bool
io_range_extend_by_bar(struct range_infer_ctx * ric,int bus,int dev,int fun,int ofs,pcireg_t curbar,pcireg_t sizebar)134cfc495a0Sdyoung io_range_extend_by_bar(struct range_infer_ctx *ric, int bus, int dev, int fun,
135cfc495a0Sdyoung int ofs, pcireg_t curbar, pcireg_t sizebar)
136cfc495a0Sdyoung {
137cfc495a0Sdyoung pci_alloc_reg_t *r;
138cfc495a0Sdyoung pci_alloc_t pal = {
139cfc495a0Sdyoung .pal_flags = 0
140cfc495a0Sdyoung , .pal_space = PCI_ALLOC_SPACE_IO
141cfc495a0Sdyoung , .pal_type = PCI_ALLOC_REGTYPE_BAR
142cfc495a0Sdyoung , .pal_reg = {{
143cfc495a0Sdyoung .r_mask = ~(pcireg_t)0
144cfc495a0Sdyoung }}
145cfc495a0Sdyoung };
146cfc495a0Sdyoung
147cfc495a0Sdyoung r = &pal.pal_reg[0];
148cfc495a0Sdyoung
149cfc495a0Sdyoung pal.pal_tag = pci_make_tag(ric->ric_pc, bus, dev, fun);
150cfc495a0Sdyoung r->r_ofs = ofs;
151cfc495a0Sdyoung r->r_val = curbar;
152cfc495a0Sdyoung
153cfc495a0Sdyoung pal.pal_addr = PCI_MAPREG_IO_ADDR(curbar);
154cfc495a0Sdyoung pal.pal_size = PCI_MAPREG_IO_SIZE(sizebar);
155cfc495a0Sdyoung
156cfc495a0Sdyoung aprint_debug("%s: %d.%d.%d base at %" PRIx64 " size %" PRIx64 "\n",
157cfc495a0Sdyoung __func__, bus, dev, fun, pal.pal_addr, pal.pal_size);
158cfc495a0Sdyoung
159cfc495a0Sdyoung return (pal.pal_size == 0) || io_range_extend(ric, &pal);
160cfc495a0Sdyoung }
161cfc495a0Sdyoung
162cfc495a0Sdyoung static bool
io_range_extend_by_vga_enable(struct range_infer_ctx * ric,int bus,int dev,int fun,pcireg_t csr,pcireg_t bcr)163cfc495a0Sdyoung io_range_extend_by_vga_enable(struct range_infer_ctx *ric,
164cfc495a0Sdyoung int bus, int dev, int fun, pcireg_t csr, pcireg_t bcr)
165cfc495a0Sdyoung {
166cfc495a0Sdyoung pci_alloc_reg_t *r;
167cfc495a0Sdyoung pci_alloc_t tpal = {
168cfc495a0Sdyoung .pal_flags = 0
169cfc495a0Sdyoung , .pal_space = PCI_ALLOC_SPACE_IO
170cfc495a0Sdyoung , .pal_type = PCI_ALLOC_REGTYPE_VGA_EN
171cfc495a0Sdyoung , .pal_reg = {{
172cfc495a0Sdyoung .r_ofs = PCI_COMMAND_STATUS_REG
173cfc495a0Sdyoung , .r_mask = PCI_COMMAND_IO_ENABLE
174cfc495a0Sdyoung }, {
175cfc495a0Sdyoung .r_ofs = PCI_BRIDGE_CONTROL_REG
17679770474Smsaitoh , .r_mask = PCI_BRIDGE_CONTROL_VGA;
177cfc495a0Sdyoung }}
178cfc495a0Sdyoung }, pal[2];
179cfc495a0Sdyoung
180cfc495a0Sdyoung aprint_debug("%s: %d.%d.%d enter\n", __func__, bus, dev, fun);
181cfc495a0Sdyoung
182cfc495a0Sdyoung if ((csr & PCI_COMMAND_IO_ENABLE) == 0 ||
18379770474Smsaitoh (bcr & PCI_BRIDGE_CONTROL_VGA) == 0) {
184cfc495a0Sdyoung aprint_debug("%s: %d.%d.%d I/O or VGA disabled\n",
185cfc495a0Sdyoung __func__, bus, dev, fun);
186cfc495a0Sdyoung return true;
187cfc495a0Sdyoung }
188cfc495a0Sdyoung
189cfc495a0Sdyoung r = &tpal.pal_reg[0];
190cfc495a0Sdyoung tpal.pal_tag = pci_make_tag(ric->ric_pc, bus, dev, fun);
191cfc495a0Sdyoung r[0].r_val = csr;
192cfc495a0Sdyoung r[1].r_val = bcr;
193cfc495a0Sdyoung
194cfc495a0Sdyoung pal[0] = pal[1] = tpal;
195cfc495a0Sdyoung
196cfc495a0Sdyoung pal[0].pal_addr = 0x3b0;
197cfc495a0Sdyoung pal[0].pal_size = 0x3bb - 0x3b0 + 1;
198cfc495a0Sdyoung
199cfc495a0Sdyoung pal[1].pal_addr = 0x3c0;
200cfc495a0Sdyoung pal[1].pal_size = 0x3df - 0x3c0 + 1;
201cfc495a0Sdyoung
202cfc495a0Sdyoung /* XXX add aliases for pal[0..1] */
203cfc495a0Sdyoung
204cfc495a0Sdyoung return io_range_extend(ric, &pal[0]) && io_range_extend(ric, &pal[1]);
205cfc495a0Sdyoung }
206cfc495a0Sdyoung
207cfc495a0Sdyoung static bool
io_range_extend_by_win(struct range_infer_ctx * ric,int bus,int dev,int fun,int ofs,int ofshigh,pcireg_t io,pcireg_t iohigh)208cfc495a0Sdyoung io_range_extend_by_win(struct range_infer_ctx *ric,
209cfc495a0Sdyoung int bus, int dev, int fun, int ofs, int ofshigh,
210cfc495a0Sdyoung pcireg_t io, pcireg_t iohigh)
211cfc495a0Sdyoung {
212cfc495a0Sdyoung const int fourkb = 4 * 1024;
213cfc495a0Sdyoung pcireg_t baser, limitr;
214cfc495a0Sdyoung pci_alloc_reg_t *r;
215cfc495a0Sdyoung pci_alloc_t pal = {
216cfc495a0Sdyoung .pal_flags = 0
217cfc495a0Sdyoung , .pal_space = PCI_ALLOC_SPACE_IO
218cfc495a0Sdyoung , .pal_type = PCI_ALLOC_REGTYPE_WIN
219cfc495a0Sdyoung , .pal_reg = {{
220cfc495a0Sdyoung .r_mask = ~(pcireg_t)0
221cfc495a0Sdyoung }}
222cfc495a0Sdyoung };
223cfc495a0Sdyoung
224cfc495a0Sdyoung r = &pal.pal_reg[0];
225cfc495a0Sdyoung
226cfc495a0Sdyoung pal.pal_tag = pci_make_tag(ric->ric_pc, bus, dev, fun);
227cfc495a0Sdyoung r[0].r_ofs = ofs;
228cfc495a0Sdyoung r[0].r_val = io;
229cfc495a0Sdyoung
23079770474Smsaitoh baser = __SHIFTOUT(io, PCI_BRIDGE_STATIO_IOBASE) >> 4;
23179770474Smsaitoh limitr = __SHIFTOUT(io, PCI_BRIDGE_STATIO_IOLIMIT) >> 4;
232cfc495a0Sdyoung
233cfc495a0Sdyoung if (PCI_BRIDGE_IO_32BITS(io)) {
234cfc495a0Sdyoung pcireg_t baseh, limith;
235cfc495a0Sdyoung
236cfc495a0Sdyoung r[1].r_mask = ~(pcireg_t)0;
237cfc495a0Sdyoung r[1].r_ofs = ofshigh;
238cfc495a0Sdyoung r[1].r_val = iohigh;
239cfc495a0Sdyoung
24079770474Smsaitoh baseh = __SHIFTOUT(iohigh, PCI_BRIDGE_IOHIGH_BASE);
24179770474Smsaitoh limith = __SHIFTOUT(iohigh, PCI_BRIDGE_IOHIGH_LIMIT);
242cfc495a0Sdyoung
243cfc495a0Sdyoung baser |= baseh << 4;
244cfc495a0Sdyoung limitr |= limith << 4;
245cfc495a0Sdyoung }
246cfc495a0Sdyoung
247cfc495a0Sdyoung /* XXX check with the PCI standard */
248cfc495a0Sdyoung if (baser > limitr)
249cfc495a0Sdyoung return true;
250cfc495a0Sdyoung
251cfc495a0Sdyoung pal.pal_addr = baser * fourkb;
252cfc495a0Sdyoung pal.pal_size = (limitr - baser + 1) * fourkb;
253cfc495a0Sdyoung
254cfc495a0Sdyoung aprint_debug("%s: %d.%d.%d window at %" PRIx64 " size %" PRIx64 "\n",
255cfc495a0Sdyoung __func__, bus, dev, fun, pal.pal_addr, pal.pal_size);
256cfc495a0Sdyoung
257cfc495a0Sdyoung return io_range_extend(ric, &pal);
258cfc495a0Sdyoung }
259cfc495a0Sdyoung
260cfc495a0Sdyoung static bool
io_range_extend_by_cbwin(struct range_infer_ctx * ric,int bus,int dev,int fun,int ofs,pcireg_t base0,pcireg_t limit0)261cfc495a0Sdyoung io_range_extend_by_cbwin(struct range_infer_ctx *ric,
262cfc495a0Sdyoung int bus, int dev, int fun, int ofs, pcireg_t base0, pcireg_t limit0)
263cfc495a0Sdyoung {
264cfc495a0Sdyoung pcireg_t base, limit;
265cfc495a0Sdyoung pci_alloc_reg_t *r;
266cfc495a0Sdyoung pci_alloc_t pal = {
267cfc495a0Sdyoung .pal_flags = 0
268cfc495a0Sdyoung , .pal_space = PCI_ALLOC_SPACE_IO
269cfc495a0Sdyoung , .pal_type = PCI_ALLOC_REGTYPE_CBWIN
270cfc495a0Sdyoung , .pal_reg = {{
271cfc495a0Sdyoung .r_mask = ~(pcireg_t)0
272cfc495a0Sdyoung }, {
273cfc495a0Sdyoung .r_mask = ~(pcireg_t)0
274cfc495a0Sdyoung }}
275cfc495a0Sdyoung };
276cfc495a0Sdyoung
277cfc495a0Sdyoung r = &pal.pal_reg[0];
278cfc495a0Sdyoung
279cfc495a0Sdyoung pal.pal_tag = pci_make_tag(ric->ric_pc, bus, dev, fun);
280cfc495a0Sdyoung r[0].r_ofs = ofs;
281cfc495a0Sdyoung r[0].r_val = base0;
282cfc495a0Sdyoung r[1].r_ofs = ofs + 4;
283cfc495a0Sdyoung r[1].r_val = limit0;
284cfc495a0Sdyoung
285cfc495a0Sdyoung base = base0 & __BITS(31, 2);
286cfc495a0Sdyoung limit = limit0 & __BITS(31, 2);
287cfc495a0Sdyoung
288cfc495a0Sdyoung if (base > limit)
289cfc495a0Sdyoung return true;
290cfc495a0Sdyoung
291cfc495a0Sdyoung pal.pal_addr = base;
292cfc495a0Sdyoung pal.pal_size = limit - base + 4; /* XXX */
293cfc495a0Sdyoung
294cfc495a0Sdyoung aprint_debug("%s: %d.%d.%d window at %" PRIx64 " size %" PRIx64 "\n",
295cfc495a0Sdyoung __func__, bus, dev, fun, pal.pal_addr, pal.pal_size);
296cfc495a0Sdyoung
297cfc495a0Sdyoung return io_range_extend(ric, &pal);
298cfc495a0Sdyoung }
299cfc495a0Sdyoung
300cfc495a0Sdyoung static void
io_range_infer(pci_chipset_tag_t pc,pcitag_t tag,void * ctx)301cfc495a0Sdyoung io_range_infer(pci_chipset_tag_t pc, pcitag_t tag, void *ctx)
302cfc495a0Sdyoung {
303cfc495a0Sdyoung struct range_infer_ctx *ric = ctx;
304cfc495a0Sdyoung pcireg_t bhlcr, limit, io;
305cfc495a0Sdyoung int bar, bus, dev, fun, hdrtype, nbar;
306cfc495a0Sdyoung bool ok = true;
307cfc495a0Sdyoung
308cfc495a0Sdyoung bhlcr = pci_conf_read(pc, tag, PCI_BHLC_REG);
309cfc495a0Sdyoung
310cfc495a0Sdyoung hdrtype = PCI_HDRTYPE_TYPE(bhlcr);
311cfc495a0Sdyoung
312cfc495a0Sdyoung pci_decompose_tag(pc, tag, &bus, &dev, &fun);
313cfc495a0Sdyoung
314cfc495a0Sdyoung switch (hdrtype) {
315cfc495a0Sdyoung case PCI_HDRTYPE_PPB:
316cfc495a0Sdyoung nbar = 2;
317cfc495a0Sdyoung /* Extract I/O windows */
318cfc495a0Sdyoung ok = ok && io_range_extend_by_win(ric, bus, dev, fun,
319cfc495a0Sdyoung PCI_BRIDGE_STATIO_REG,
320cfc495a0Sdyoung PCI_BRIDGE_IOHIGH_REG,
321cfc495a0Sdyoung pci_conf_read(pc, tag, PCI_BRIDGE_STATIO_REG),
322cfc495a0Sdyoung pci_conf_read(pc, tag, PCI_BRIDGE_IOHIGH_REG));
323cfc495a0Sdyoung ok = ok && io_range_extend_by_vga_enable(ric, bus, dev, fun,
324cfc495a0Sdyoung pci_conf_read(pc, tag, PCI_COMMAND_STATUS_REG),
325cfc495a0Sdyoung pci_conf_read(pc, tag, PCI_BRIDGE_CONTROL_REG));
326cfc495a0Sdyoung break;
327cfc495a0Sdyoung case PCI_HDRTYPE_PCB:
328cfc495a0Sdyoung /* Extract I/O windows */
329cfc495a0Sdyoung io = pci_conf_read(pc, tag, PCI_CB_IOBASE0);
330cfc495a0Sdyoung limit = pci_conf_read(pc, tag, PCI_CB_IOLIMIT0);
331cfc495a0Sdyoung ok = ok && io_range_extend_by_cbwin(ric, bus, dev, fun,
332cfc495a0Sdyoung PCI_CB_IOBASE0, io, limit);
333cfc495a0Sdyoung io = pci_conf_read(pc, tag, PCI_CB_IOBASE1);
334cfc495a0Sdyoung limit = pci_conf_read(pc, tag, PCI_CB_IOLIMIT1);
335cfc495a0Sdyoung ok = ok && io_range_extend_by_cbwin(ric, bus, dev, fun,
336cfc495a0Sdyoung PCI_CB_IOBASE1, io, limit);
337cfc495a0Sdyoung nbar = 1;
338cfc495a0Sdyoung break;
339cfc495a0Sdyoung case PCI_HDRTYPE_DEVICE:
340cfc495a0Sdyoung nbar = 6;
341cfc495a0Sdyoung break;
342cfc495a0Sdyoung default:
343cfc495a0Sdyoung aprint_debug("%s: unknown header type %d at %d.%d.%d\n",
344cfc495a0Sdyoung __func__, hdrtype, bus, dev, fun);
345cfc495a0Sdyoung return;
346cfc495a0Sdyoung }
347cfc495a0Sdyoung
348cfc495a0Sdyoung for (bar = 0; bar < nbar; bar++) {
349cfc495a0Sdyoung pcireg_t basebar, sizebar;
350cfc495a0Sdyoung
351cfc495a0Sdyoung basebar = pci_conf_read(pc, tag, PCI_BAR(bar));
352cfc495a0Sdyoung pci_conf_write(pc, tag, PCI_BAR(bar), 0xffffffff);
353cfc495a0Sdyoung sizebar = pci_conf_read(pc, tag, PCI_BAR(bar));
354cfc495a0Sdyoung pci_conf_write(pc, tag, PCI_BAR(bar), basebar);
355cfc495a0Sdyoung
356cfc495a0Sdyoung if (sizebar == 0)
357cfc495a0Sdyoung continue;
358cfc495a0Sdyoung if (PCI_MAPREG_TYPE(sizebar) != PCI_MAPREG_TYPE_IO)
359cfc495a0Sdyoung continue;
360cfc495a0Sdyoung
361cfc495a0Sdyoung ok = ok && io_range_extend_by_bar(ric, bus, dev, fun,
362cfc495a0Sdyoung PCI_BAR(bar), basebar, sizebar);
363cfc495a0Sdyoung }
364cfc495a0Sdyoung if (!ok) {
365cfc495a0Sdyoung aprint_verbose("I/O range inference failed at PCI %d.%d.%d\n",
366cfc495a0Sdyoung bus, dev, fun);
367cfc495a0Sdyoung }
368cfc495a0Sdyoung }
369cfc495a0Sdyoung
370cfc495a0Sdyoung static bool
mmio_range_extend(struct range_infer_ctx * ric,const pci_alloc_t * pal)371cfc495a0Sdyoung mmio_range_extend(struct range_infer_ctx *ric, const pci_alloc_t *pal)
372cfc495a0Sdyoung {
373cfc495a0Sdyoung if (ric->ric_mmio_bottom > pal->pal_addr)
374cfc495a0Sdyoung ric->ric_mmio_bottom = pal->pal_addr;
375cfc495a0Sdyoung if (ric->ric_mmio_top < pal->pal_addr + pal->pal_size)
376cfc495a0Sdyoung ric->ric_mmio_top = pal->pal_addr + pal->pal_size;
377cfc495a0Sdyoung
378cfc495a0Sdyoung return pci_alloc_linkdup(&ric->ric_pals, pal);
379cfc495a0Sdyoung }
380cfc495a0Sdyoung
381cfc495a0Sdyoung static bool
mmio_range_extend_by_bar(struct range_infer_ctx * ric,int bus,int dev,int fun,int ofs,pcireg_t curbar,pcireg_t sizebar)382766e6e09Smsaitoh mmio_range_extend_by_bar(struct range_infer_ctx *ric, int bus, int dev,
383766e6e09Smsaitoh int fun, int ofs, pcireg_t curbar, pcireg_t sizebar)
384cfc495a0Sdyoung {
385cfc495a0Sdyoung int type;
386cfc495a0Sdyoung bool prefetchable;
387cfc495a0Sdyoung pci_alloc_reg_t *r;
388cfc495a0Sdyoung pci_alloc_t pal = {
389cfc495a0Sdyoung .pal_flags = 0
390cfc495a0Sdyoung , .pal_space = PCI_ALLOC_SPACE_MEM
391cfc495a0Sdyoung , .pal_type = PCI_ALLOC_REGTYPE_BAR
392cfc495a0Sdyoung , .pal_reg = {{
393cfc495a0Sdyoung .r_mask = ~(pcireg_t)0
394cfc495a0Sdyoung }}
395cfc495a0Sdyoung };
396cfc495a0Sdyoung
397cfc495a0Sdyoung r = &pal.pal_reg[0];
398cfc495a0Sdyoung
399cfc495a0Sdyoung pal.pal_tag = pci_make_tag(ric->ric_pc, bus, dev, fun);
400cfc495a0Sdyoung r->r_ofs = ofs;
401cfc495a0Sdyoung r->r_val = curbar;
402cfc495a0Sdyoung
403cfc495a0Sdyoung pal.pal_addr = PCI_MAPREG_MEM_ADDR(curbar);
404cfc495a0Sdyoung
405cfc495a0Sdyoung type = PCI_MAPREG_MEM_TYPE(curbar);
406cfc495a0Sdyoung prefetchable = PCI_MAPREG_MEM_PREFETCHABLE(curbar);
407cfc495a0Sdyoung
408cfc495a0Sdyoung if (prefetchable)
409cfc495a0Sdyoung pal.pal_flags |= PCI_ALLOC_F_PREFETCHABLE;
410cfc495a0Sdyoung
411cfc495a0Sdyoung switch (type) {
412cfc495a0Sdyoung case PCI_MAPREG_MEM_TYPE_32BIT:
413cfc495a0Sdyoung pal.pal_size = PCI_MAPREG_MEM_SIZE(sizebar);
414cfc495a0Sdyoung break;
415cfc495a0Sdyoung case PCI_MAPREG_MEM_TYPE_64BIT:
416cfc495a0Sdyoung pal.pal_size = PCI_MAPREG_MEM64_SIZE(sizebar);
417cfc495a0Sdyoung break;
418cfc495a0Sdyoung case PCI_MAPREG_MEM_TYPE_32BIT_1M:
419cfc495a0Sdyoung default:
420cfc495a0Sdyoung aprint_debug("%s: ignored memory type %d at %d.%d.%d\n",
421cfc495a0Sdyoung __func__, type, bus, dev, fun);
422cfc495a0Sdyoung return false;
423cfc495a0Sdyoung }
424cfc495a0Sdyoung
425cfc495a0Sdyoung aprint_debug("%s: %d.%d.%d base at %" PRIx64 " size %" PRIx64 "\n",
426cfc495a0Sdyoung __func__, bus, dev, fun, pal.pal_addr, pal.pal_size);
427cfc495a0Sdyoung
428cfc495a0Sdyoung return (pal.pal_size == 0) || mmio_range_extend(ric, &pal);
429cfc495a0Sdyoung }
430cfc495a0Sdyoung
431cfc495a0Sdyoung static bool
mmio_range_extend_by_vga_enable(struct range_infer_ctx * ric,int bus,int dev,int fun,pcireg_t csr,pcireg_t bcr)432cfc495a0Sdyoung mmio_range_extend_by_vga_enable(struct range_infer_ctx *ric,
433cfc495a0Sdyoung int bus, int dev, int fun, pcireg_t csr, pcireg_t bcr)
434cfc495a0Sdyoung {
435cfc495a0Sdyoung pci_alloc_reg_t *r;
436cfc495a0Sdyoung pci_alloc_t tpal = {
437cfc495a0Sdyoung .pal_flags = PCI_ALLOC_F_PREFETCHABLE /* XXX a guess */
438cfc495a0Sdyoung , .pal_space = PCI_ALLOC_SPACE_MEM
439cfc495a0Sdyoung , .pal_type = PCI_ALLOC_REGTYPE_VGA_EN
440cfc495a0Sdyoung , .pal_reg = {{
441cfc495a0Sdyoung .r_ofs = PCI_COMMAND_STATUS_REG
442cfc495a0Sdyoung , .r_mask = PCI_COMMAND_MEM_ENABLE
443cfc495a0Sdyoung }, {
444cfc495a0Sdyoung .r_ofs = PCI_BRIDGE_CONTROL_REG
44579770474Smsaitoh , .r_mask = PCI_BRIDGE_CONTROL_VGA
446cfc495a0Sdyoung }}
447cfc495a0Sdyoung }, pal;
448cfc495a0Sdyoung
449cfc495a0Sdyoung aprint_debug("%s: %d.%d.%d enter\n", __func__, bus, dev, fun);
450cfc495a0Sdyoung
451cfc495a0Sdyoung if ((csr & PCI_COMMAND_MEM_ENABLE) == 0 ||
45279770474Smsaitoh (bcr & PCI_BRIDGE_CONTROL_VGA) == 0) {
453cfc495a0Sdyoung aprint_debug("%s: %d.%d.%d memory or VGA disabled\n",
454cfc495a0Sdyoung __func__, bus, dev, fun);
455cfc495a0Sdyoung return true;
456cfc495a0Sdyoung }
457cfc495a0Sdyoung
458cfc495a0Sdyoung r = &tpal.pal_reg[0];
459cfc495a0Sdyoung tpal.pal_tag = pci_make_tag(ric->ric_pc, bus, dev, fun);
460cfc495a0Sdyoung r[0].r_val = csr;
461cfc495a0Sdyoung r[1].r_val = bcr;
462cfc495a0Sdyoung
463cfc495a0Sdyoung pal = tpal;
464cfc495a0Sdyoung
465cfc495a0Sdyoung pal.pal_addr = 0xa0000;
466cfc495a0Sdyoung pal.pal_size = 0xbffff - 0xa0000 + 1;
467cfc495a0Sdyoung
468cfc495a0Sdyoung return mmio_range_extend(ric, &pal);
469cfc495a0Sdyoung }
470cfc495a0Sdyoung
471cfc495a0Sdyoung static bool
mmio_range_extend_by_win(struct range_infer_ctx * ric,int bus,int dev,int fun,int ofs,pcireg_t mem)472cfc495a0Sdyoung mmio_range_extend_by_win(struct range_infer_ctx *ric,
473cfc495a0Sdyoung int bus, int dev, int fun, int ofs, pcireg_t mem)
474cfc495a0Sdyoung {
475cfc495a0Sdyoung const int onemeg = 1024 * 1024;
476cfc495a0Sdyoung pcireg_t baser, limitr;
477cfc495a0Sdyoung pci_alloc_reg_t *r;
478cfc495a0Sdyoung pci_alloc_t pal = {
479cfc495a0Sdyoung .pal_flags = 0
480cfc495a0Sdyoung , .pal_space = PCI_ALLOC_SPACE_MEM
481cfc495a0Sdyoung , .pal_type = PCI_ALLOC_REGTYPE_WIN
482cfc495a0Sdyoung , .pal_reg = {{
483cfc495a0Sdyoung .r_mask = ~(pcireg_t)0
484cfc495a0Sdyoung }}
485cfc495a0Sdyoung };
486cfc495a0Sdyoung
487cfc495a0Sdyoung r = &pal.pal_reg[0];
488cfc495a0Sdyoung
489cfc495a0Sdyoung pal.pal_tag = pci_make_tag(ric->ric_pc, bus, dev, fun);
490cfc495a0Sdyoung r->r_ofs = ofs;
491cfc495a0Sdyoung r->r_val = mem;
492cfc495a0Sdyoung
493cfc495a0Sdyoung baser = (mem >> PCI_BRIDGE_MEMORY_BASE_SHIFT) &
494cfc495a0Sdyoung PCI_BRIDGE_MEMORY_BASE_MASK;
495cfc495a0Sdyoung limitr = (mem >> PCI_BRIDGE_MEMORY_LIMIT_SHIFT) &
496cfc495a0Sdyoung PCI_BRIDGE_MEMORY_LIMIT_MASK;
497cfc495a0Sdyoung
498cfc495a0Sdyoung /* XXX check with the PCI standard */
499cfc495a0Sdyoung if (baser > limitr || limitr == 0)
500cfc495a0Sdyoung return true;
501cfc495a0Sdyoung
502cfc495a0Sdyoung pal.pal_addr = baser * onemeg;
503cfc495a0Sdyoung pal.pal_size = (limitr - baser + 1) * onemeg;
504cfc495a0Sdyoung
505cfc495a0Sdyoung aprint_debug("%s: %d.%d.%d window at %" PRIx64 " size %" PRIx64 "\n",
506cfc495a0Sdyoung __func__, bus, dev, fun, pal.pal_addr, pal.pal_size);
507cfc495a0Sdyoung
508cfc495a0Sdyoung return mmio_range_extend(ric, &pal);
509cfc495a0Sdyoung }
510cfc495a0Sdyoung
511cfc495a0Sdyoung static bool
mmio_range_extend_by_prememwin(struct range_infer_ctx * ric,int bus,int dev,int fun,int ofs,pcireg_t mem,int hibaseofs,pcireg_t hibase,int hilimitofs,pcireg_t hilimit)512cfc495a0Sdyoung mmio_range_extend_by_prememwin(struct range_infer_ctx *ric,
513cfc495a0Sdyoung int bus, int dev, int fun, int ofs, pcireg_t mem,
514cfc495a0Sdyoung int hibaseofs, pcireg_t hibase,
515cfc495a0Sdyoung int hilimitofs, pcireg_t hilimit)
516cfc495a0Sdyoung {
517cfc495a0Sdyoung const int onemeg = 1024 * 1024;
518cfc495a0Sdyoung uint64_t baser, limitr;
519cfc495a0Sdyoung pci_alloc_reg_t *r;
520cfc495a0Sdyoung pci_alloc_t pal = {
521cfc495a0Sdyoung .pal_flags = PCI_ALLOC_F_PREFETCHABLE
522cfc495a0Sdyoung , .pal_space = PCI_ALLOC_SPACE_MEM
523cfc495a0Sdyoung , .pal_type = PCI_ALLOC_REGTYPE_WIN
524cfc495a0Sdyoung , .pal_reg = {{
525cfc495a0Sdyoung .r_mask = ~(pcireg_t)0
526cfc495a0Sdyoung }}
527cfc495a0Sdyoung };
528cfc495a0Sdyoung
529cfc495a0Sdyoung r = &pal.pal_reg[0];
530cfc495a0Sdyoung
531cfc495a0Sdyoung pal.pal_tag = pci_make_tag(ric->ric_pc, bus, dev, fun);
532cfc495a0Sdyoung r[0].r_ofs = ofs;
533cfc495a0Sdyoung r[0].r_val = mem;
534cfc495a0Sdyoung
535cfc495a0Sdyoung baser = (mem >> PCI_BRIDGE_PREFETCHMEM_BASE_SHIFT) &
536cfc495a0Sdyoung PCI_BRIDGE_PREFETCHMEM_BASE_MASK;
537cfc495a0Sdyoung limitr = (mem >> PCI_BRIDGE_PREFETCHMEM_LIMIT_SHIFT) &
538cfc495a0Sdyoung PCI_BRIDGE_PREFETCHMEM_LIMIT_MASK;
539cfc495a0Sdyoung
540cfc495a0Sdyoung if (PCI_BRIDGE_PREFETCHMEM_64BITS(mem)) {
541cfc495a0Sdyoung r[1].r_mask = r[2].r_mask = ~(pcireg_t)0;
542cfc495a0Sdyoung r[1].r_ofs = hibaseofs;
543cfc495a0Sdyoung r[1].r_val = hibase;
544cfc495a0Sdyoung r[2].r_ofs = hilimitofs;
545cfc495a0Sdyoung r[2].r_val = hilimit;
546cfc495a0Sdyoung
547cfc495a0Sdyoung baser |= hibase << 12;
548cfc495a0Sdyoung limitr |= hibase << 12;
549cfc495a0Sdyoung }
550cfc495a0Sdyoung
551cfc495a0Sdyoung /* XXX check with the PCI standard */
552cfc495a0Sdyoung if (baser > limitr || limitr == 0)
553cfc495a0Sdyoung return true;
554cfc495a0Sdyoung
555cfc495a0Sdyoung pal.pal_addr = baser * onemeg;
556cfc495a0Sdyoung pal.pal_size = (limitr - baser + 1) * onemeg;
557cfc495a0Sdyoung
558cfc495a0Sdyoung aprint_debug("%s: %d.%d.%d window at %" PRIx64 " size %" PRIx64 "\n",
559cfc495a0Sdyoung __func__, bus, dev, fun, pal.pal_addr, pal.pal_size);
560cfc495a0Sdyoung
561cfc495a0Sdyoung return mmio_range_extend(ric, &pal);
562cfc495a0Sdyoung }
563cfc495a0Sdyoung
564cfc495a0Sdyoung static bool
mmio_range_extend_by_cbwin(struct range_infer_ctx * ric,int bus,int dev,int fun,int ofs,pcireg_t base,pcireg_t limit,bool prefetchable)565cfc495a0Sdyoung mmio_range_extend_by_cbwin(struct range_infer_ctx *ric,
566cfc495a0Sdyoung int bus, int dev, int fun, int ofs, pcireg_t base, pcireg_t limit,
567cfc495a0Sdyoung bool prefetchable)
568cfc495a0Sdyoung {
569cfc495a0Sdyoung pci_alloc_reg_t *r;
570cfc495a0Sdyoung pci_alloc_t pal = {
571cfc495a0Sdyoung .pal_flags = 0
572cfc495a0Sdyoung , .pal_space = PCI_ALLOC_SPACE_MEM
573cfc495a0Sdyoung , .pal_type = PCI_ALLOC_REGTYPE_CBWIN
574cfc495a0Sdyoung , .pal_reg = {{
575cfc495a0Sdyoung .r_mask = ~(pcireg_t)0
576cfc495a0Sdyoung }, {
577cfc495a0Sdyoung .r_mask = ~(pcireg_t)0
578cfc495a0Sdyoung }}
579cfc495a0Sdyoung };
580cfc495a0Sdyoung
581cfc495a0Sdyoung r = &pal.pal_reg[0];
582cfc495a0Sdyoung
583cfc495a0Sdyoung if (prefetchable)
584cfc495a0Sdyoung pal.pal_flags |= PCI_ALLOC_F_PREFETCHABLE;
585cfc495a0Sdyoung
586cfc495a0Sdyoung pal.pal_tag = pci_make_tag(ric->ric_pc, bus, dev, fun);
587cfc495a0Sdyoung r[0].r_ofs = ofs;
588cfc495a0Sdyoung r[0].r_val = base;
589cfc495a0Sdyoung r[1].r_ofs = ofs + 4;
590cfc495a0Sdyoung r[1].r_val = limit;
591cfc495a0Sdyoung
592cfc495a0Sdyoung if (base > limit)
593cfc495a0Sdyoung return true;
594cfc495a0Sdyoung
595cfc495a0Sdyoung if (limit == 0)
596cfc495a0Sdyoung return true;
597cfc495a0Sdyoung
598cfc495a0Sdyoung pal.pal_addr = base;
599cfc495a0Sdyoung pal.pal_size = limit - base + 4096;
600cfc495a0Sdyoung
601cfc495a0Sdyoung aprint_debug("%s: %d.%d.%d window at %" PRIx64 " size %" PRIx64 "\n",
602cfc495a0Sdyoung __func__, bus, dev, fun, pal.pal_addr, pal.pal_size);
603cfc495a0Sdyoung
604cfc495a0Sdyoung return mmio_range_extend(ric, &pal);
605cfc495a0Sdyoung }
606cfc495a0Sdyoung
607cfc495a0Sdyoung static void
mmio_range_infer(pci_chipset_tag_t pc,pcitag_t tag,void * ctx)608cfc495a0Sdyoung mmio_range_infer(pci_chipset_tag_t pc, pcitag_t tag, void *ctx)
609cfc495a0Sdyoung {
610cfc495a0Sdyoung struct range_infer_ctx *ric = ctx;
611cfc495a0Sdyoung pcireg_t bcr, bhlcr, limit, mem, premem, hiprebase, hiprelimit;
612cfc495a0Sdyoung int bar, bus, dev, fun, hdrtype, nbar;
613cfc495a0Sdyoung bool ok = true;
614cfc495a0Sdyoung
615cfc495a0Sdyoung bhlcr = pci_conf_read(pc, tag, PCI_BHLC_REG);
616cfc495a0Sdyoung
617cfc495a0Sdyoung hdrtype = PCI_HDRTYPE_TYPE(bhlcr);
618cfc495a0Sdyoung
619cfc495a0Sdyoung pci_decompose_tag(pc, tag, &bus, &dev, &fun);
620cfc495a0Sdyoung
621cfc495a0Sdyoung switch (hdrtype) {
622cfc495a0Sdyoung case PCI_HDRTYPE_PPB:
623cfc495a0Sdyoung nbar = 2;
624cfc495a0Sdyoung /* Extract memory windows */
625cfc495a0Sdyoung ok = ok && mmio_range_extend_by_win(ric, bus, dev, fun,
626cfc495a0Sdyoung PCI_BRIDGE_MEMORY_REG,
627cfc495a0Sdyoung pci_conf_read(pc, tag, PCI_BRIDGE_MEMORY_REG));
628cfc495a0Sdyoung premem = pci_conf_read(pc, tag, PCI_BRIDGE_PREFETCHMEM_REG);
629cfc495a0Sdyoung if (PCI_BRIDGE_PREFETCHMEM_64BITS(premem)) {
630cfc495a0Sdyoung aprint_debug("%s: 64-bit prefetchable memory window "
631cfc495a0Sdyoung "at %d.%d.%d\n", __func__, bus, dev, fun);
632cfc495a0Sdyoung hiprebase = pci_conf_read(pc, tag,
633cfc495a0Sdyoung PCI_BRIDGE_PREFETCHBASE32_REG);
634cfc495a0Sdyoung hiprelimit = pci_conf_read(pc, tag,
635cfc495a0Sdyoung PCI_BRIDGE_PREFETCHLIMIT32_REG);
636cfc495a0Sdyoung } else
637cfc495a0Sdyoung hiprebase = hiprelimit = 0;
638cfc495a0Sdyoung ok = ok &&
639cfc495a0Sdyoung mmio_range_extend_by_prememwin(ric, bus, dev, fun,
640cfc495a0Sdyoung PCI_BRIDGE_PREFETCHMEM_REG, premem,
641cfc495a0Sdyoung PCI_BRIDGE_PREFETCHBASE32_REG, hiprebase,
642cfc495a0Sdyoung PCI_BRIDGE_PREFETCHLIMIT32_REG, hiprelimit) &&
643cfc495a0Sdyoung mmio_range_extend_by_vga_enable(ric, bus, dev, fun,
644cfc495a0Sdyoung pci_conf_read(pc, tag, PCI_COMMAND_STATUS_REG),
645cfc495a0Sdyoung pci_conf_read(pc, tag, PCI_BRIDGE_CONTROL_REG));
646cfc495a0Sdyoung break;
647cfc495a0Sdyoung case PCI_HDRTYPE_PCB:
648cfc495a0Sdyoung /* Extract memory windows */
649cfc495a0Sdyoung bcr = pci_conf_read(pc, tag, PCI_BRIDGE_CONTROL_REG);
650cfc495a0Sdyoung mem = pci_conf_read(pc, tag, PCI_CB_MEMBASE0);
651cfc495a0Sdyoung limit = pci_conf_read(pc, tag, PCI_CB_MEMLIMIT0);
652cfc495a0Sdyoung ok = ok && mmio_range_extend_by_cbwin(ric, bus, dev, fun,
653cfc495a0Sdyoung PCI_CB_MEMBASE0, mem, limit,
654cfc495a0Sdyoung (bcr & CB_BCR_PREFETCH_MEMWIN0) != 0);
655cfc495a0Sdyoung mem = pci_conf_read(pc, tag, PCI_CB_MEMBASE1);
656cfc495a0Sdyoung limit = pci_conf_read(pc, tag, PCI_CB_MEMLIMIT1);
657cfc495a0Sdyoung ok = ok && mmio_range_extend_by_cbwin(ric, bus, dev, fun,
658cfc495a0Sdyoung PCI_CB_MEMBASE1, mem, limit,
659cfc495a0Sdyoung (bcr & CB_BCR_PREFETCH_MEMWIN1) != 0);
660cfc495a0Sdyoung nbar = 1;
661cfc495a0Sdyoung break;
662cfc495a0Sdyoung case PCI_HDRTYPE_DEVICE:
663cfc495a0Sdyoung nbar = 6;
664cfc495a0Sdyoung break;
665cfc495a0Sdyoung default:
666cfc495a0Sdyoung aprint_debug("%s: unknown header type %d at %d.%d.%d\n",
667cfc495a0Sdyoung __func__, hdrtype, bus, dev, fun);
668cfc495a0Sdyoung return;
669cfc495a0Sdyoung }
670cfc495a0Sdyoung
671cfc495a0Sdyoung for (bar = 0; bar < nbar; bar++) {
672cfc495a0Sdyoung pcireg_t basebar, sizebar;
673cfc495a0Sdyoung
674cfc495a0Sdyoung basebar = pci_conf_read(pc, tag, PCI_BAR(bar));
675cfc495a0Sdyoung pci_conf_write(pc, tag, PCI_BAR(bar), 0xffffffff);
676cfc495a0Sdyoung sizebar = pci_conf_read(pc, tag, PCI_BAR(bar));
677cfc495a0Sdyoung pci_conf_write(pc, tag, PCI_BAR(bar), basebar);
678cfc495a0Sdyoung
679cfc495a0Sdyoung if (sizebar == 0)
680cfc495a0Sdyoung continue;
681cfc495a0Sdyoung if (PCI_MAPREG_TYPE(sizebar) != PCI_MAPREG_TYPE_MEM)
682cfc495a0Sdyoung continue;
683cfc495a0Sdyoung
684cfc495a0Sdyoung ok = ok && mmio_range_extend_by_bar(ric, bus, dev, fun,
685cfc495a0Sdyoung PCI_BAR(bar), basebar, sizebar);
686cfc495a0Sdyoung }
687cfc495a0Sdyoung if (!ok) {
688cfc495a0Sdyoung aprint_verbose("MMIO range inference failed at PCI %d.%d.%d\n",
689cfc495a0Sdyoung bus, dev, fun);
690cfc495a0Sdyoung }
691cfc495a0Sdyoung }
692cfc495a0Sdyoung
693cfc495a0Sdyoung static const char *
pci_alloc_regtype_string(const pci_alloc_regtype_t t)694cfc495a0Sdyoung pci_alloc_regtype_string(const pci_alloc_regtype_t t)
695cfc495a0Sdyoung {
696cfc495a0Sdyoung switch (t) {
697cfc495a0Sdyoung case PCI_ALLOC_REGTYPE_BAR:
698cfc495a0Sdyoung return "bar";
699cfc495a0Sdyoung case PCI_ALLOC_REGTYPE_WIN:
700cfc495a0Sdyoung case PCI_ALLOC_REGTYPE_CBWIN:
701cfc495a0Sdyoung return "window";
702cfc495a0Sdyoung case PCI_ALLOC_REGTYPE_VGA_EN:
703cfc495a0Sdyoung return "vga-enable";
704cfc495a0Sdyoung default:
705cfc495a0Sdyoung return "<unknown>";
706cfc495a0Sdyoung }
707cfc495a0Sdyoung }
708cfc495a0Sdyoung
709cfc495a0Sdyoung static void
pci_alloc_print(pci_chipset_tag_t pc,const pci_alloc_t * pal)710cfc495a0Sdyoung pci_alloc_print(pci_chipset_tag_t pc, const pci_alloc_t *pal)
711cfc495a0Sdyoung {
712cfc495a0Sdyoung int bus, dev, fun;
713cfc495a0Sdyoung const pci_alloc_reg_t *r;
714cfc495a0Sdyoung
715cfc495a0Sdyoung pci_decompose_tag(pc, pal->pal_tag, &bus, &dev, &fun);
716cfc495a0Sdyoung r = &pal->pal_reg[0];
717cfc495a0Sdyoung
718cfc495a0Sdyoung aprint_normal("%s range [0x%08" PRIx64 ", 0x%08" PRIx64 ")"
719cfc495a0Sdyoung " at %d.%d.%d %s%s 0x%02x\n",
720cfc495a0Sdyoung (pal->pal_space == PCI_ALLOC_SPACE_IO) ? "IO" : "MMIO",
721cfc495a0Sdyoung pal->pal_addr, pal->pal_addr + pal->pal_size,
722cfc495a0Sdyoung bus, dev, fun,
723cfc495a0Sdyoung (pal->pal_flags & PCI_ALLOC_F_PREFETCHABLE) ? "prefetchable " : "",
724cfc495a0Sdyoung pci_alloc_regtype_string(pal->pal_type),
725cfc495a0Sdyoung r->r_ofs);
726cfc495a0Sdyoung }
727cfc495a0Sdyoung
728cfc495a0Sdyoung prop_dictionary_t pci_rsrc_dict = NULL;
729cfc495a0Sdyoung
730cfc495a0Sdyoung static bool
pci_range_record(pci_chipset_tag_t pc,prop_array_t rsvns,pci_alloc_list_t * pals,pci_alloc_space_t space)731cfc495a0Sdyoung pci_range_record(pci_chipset_tag_t pc, prop_array_t rsvns,
732cfc495a0Sdyoung pci_alloc_list_t *pals, pci_alloc_space_t space)
733cfc495a0Sdyoung {
734cfc495a0Sdyoung int bus, dev, fun, i;
735cfc495a0Sdyoung prop_array_t regs;
736cfc495a0Sdyoung prop_dictionary_t reg;
737cfc495a0Sdyoung const pci_alloc_t *pal;
738cfc495a0Sdyoung const pci_alloc_reg_t *r;
739cfc495a0Sdyoung prop_dictionary_t rsvn;
740cfc495a0Sdyoung
741cfc495a0Sdyoung TAILQ_FOREACH(pal, pals, pal_link) {
742cfc495a0Sdyoung bool ok = true;
743cfc495a0Sdyoung
744cfc495a0Sdyoung r = &pal->pal_reg[0];
745cfc495a0Sdyoung
746cfc495a0Sdyoung if (pal->pal_space != space)
747cfc495a0Sdyoung continue;
748cfc495a0Sdyoung
749cfc495a0Sdyoung if ((rsvn = prop_dictionary_create()) == NULL)
750cfc495a0Sdyoung return false;
751cfc495a0Sdyoung
752cfc495a0Sdyoung if ((regs = prop_array_create()) == NULL) {
753cfc495a0Sdyoung prop_object_release(rsvn);
754cfc495a0Sdyoung return false;
755cfc495a0Sdyoung }
756cfc495a0Sdyoung
757cfc495a0Sdyoung if (!prop_dictionary_set(rsvn, "regs", regs)) {
758cfc495a0Sdyoung prop_object_release(rsvn);
759cfc495a0Sdyoung prop_object_release(regs);
760cfc495a0Sdyoung return false;
761cfc495a0Sdyoung }
762cfc495a0Sdyoung
763cfc495a0Sdyoung for (i = 0; i < __arraycount(pal->pal_reg); i++) {
764cfc495a0Sdyoung r = &pal->pal_reg[i];
765cfc495a0Sdyoung
766cfc495a0Sdyoung if (r->r_mask == 0)
767cfc495a0Sdyoung break;
768cfc495a0Sdyoung
769cfc495a0Sdyoung ok = (reg = prop_dictionary_create()) != NULL;
770cfc495a0Sdyoung if (!ok)
771cfc495a0Sdyoung break;
772cfc495a0Sdyoung
773cfc495a0Sdyoung ok = prop_dictionary_set_uint16(reg, "offset",
774cfc495a0Sdyoung r->r_ofs) &&
775cfc495a0Sdyoung prop_dictionary_set_uint32(reg, "val", r->r_val) &&
776cfc495a0Sdyoung prop_dictionary_set_uint32(reg, "mask",
777cfc495a0Sdyoung r->r_mask) && prop_array_add(regs, reg);
778cfc495a0Sdyoung if (!ok) {
779cfc495a0Sdyoung prop_object_release(reg);
780cfc495a0Sdyoung break;
781cfc495a0Sdyoung }
782cfc495a0Sdyoung }
783cfc495a0Sdyoung
784cfc495a0Sdyoung pci_decompose_tag(pc, pal->pal_tag, &bus, &dev, &fun);
785cfc495a0Sdyoung
786cfc495a0Sdyoung ok = ok &&
787*6b5045cdSchristos prop_dictionary_set_string_nocopy(rsvn, "type",
788cfc495a0Sdyoung pci_alloc_regtype_string(pal->pal_type)) &&
789cfc495a0Sdyoung prop_dictionary_set_uint64(rsvn, "address",
790cfc495a0Sdyoung pal->pal_addr) &&
791cfc495a0Sdyoung prop_dictionary_set_uint64(rsvn, "size", pal->pal_size) &&
792cfc495a0Sdyoung prop_dictionary_set_uint8(rsvn, "bus", bus) &&
793cfc495a0Sdyoung prop_dictionary_set_uint8(rsvn, "device", dev) &&
794cfc495a0Sdyoung prop_dictionary_set_uint8(rsvn, "function", fun) &&
795cfc495a0Sdyoung prop_array_add(rsvns, rsvn);
796cfc495a0Sdyoung prop_object_release(rsvn);
797cfc495a0Sdyoung if (!ok)
798cfc495a0Sdyoung return false;
799cfc495a0Sdyoung }
800cfc495a0Sdyoung return true;
801cfc495a0Sdyoung }
802cfc495a0Sdyoung
803cfc495a0Sdyoung prop_dictionary_t
pci_rsrc_filter(prop_dictionary_t rsrcs0,bool (* predicate)(void *,prop_dictionary_t),void * arg)804cfc495a0Sdyoung pci_rsrc_filter(prop_dictionary_t rsrcs0,
805cfc495a0Sdyoung bool (*predicate)(void *, prop_dictionary_t), void *arg)
806cfc495a0Sdyoung {
807cfc495a0Sdyoung int i, space;
808cfc495a0Sdyoung prop_dictionary_t rsrcs;
809cfc495a0Sdyoung prop_array_t rsvns;
810cfc495a0Sdyoung ppath_t *op, *p;
811cfc495a0Sdyoung
812cfc495a0Sdyoung if ((rsrcs = prop_dictionary_copy(rsrcs0)) == NULL)
813cfc495a0Sdyoung return NULL;
814cfc495a0Sdyoung
815cfc495a0Sdyoung for (space = 0; space < 2; space++) {
816cfc495a0Sdyoung op = p = ppath_create();
817cfc495a0Sdyoung p = ppath_push_key(p, (space == 0) ? "memory" : "io");
818cfc495a0Sdyoung p = ppath_push_key(p, "bios-reservations");
819cfc495a0Sdyoung if (p == NULL) {
820cfc495a0Sdyoung ppath_release(op);
821cfc495a0Sdyoung return NULL;
822cfc495a0Sdyoung }
823cfc495a0Sdyoung if ((rsvns = ppath_lookup(rsrcs0, p)) == NULL) {
824cfc495a0Sdyoung printf("%s: reservations not found\n", __func__);
825cfc495a0Sdyoung ppath_release(p);
826cfc495a0Sdyoung return NULL;
827cfc495a0Sdyoung }
828cfc495a0Sdyoung for (i = prop_array_count(rsvns); --i >= 0; ) {
829cfc495a0Sdyoung prop_dictionary_t rsvn;
830cfc495a0Sdyoung
831cfc495a0Sdyoung if ((p = ppath_push_idx(p, i)) == NULL) {
832cfc495a0Sdyoung printf("%s: ppath_push_idx\n", __func__);
833cfc495a0Sdyoung ppath_release(op);
834cfc495a0Sdyoung prop_object_release(rsrcs);
835cfc495a0Sdyoung return NULL;
836cfc495a0Sdyoung }
837cfc495a0Sdyoung
838cfc495a0Sdyoung rsvn = ppath_lookup(rsrcs0, p);
839cfc495a0Sdyoung
840cfc495a0Sdyoung KASSERT(rsvn != NULL);
841cfc495a0Sdyoung
842cfc495a0Sdyoung if (!(*predicate)(arg, rsvn)) {
843cfc495a0Sdyoung ppath_copydel_object((prop_object_t)rsrcs0,
844cfc495a0Sdyoung (prop_object_t *)&rsrcs, p);
845cfc495a0Sdyoung }
846cfc495a0Sdyoung
847cfc495a0Sdyoung if ((p = ppath_pop(p, NULL)) == NULL) {
848cfc495a0Sdyoung printf("%s: ppath_pop\n", __func__);
849cfc495a0Sdyoung ppath_release(p);
850cfc495a0Sdyoung prop_object_release(rsrcs);
851cfc495a0Sdyoung return NULL;
852cfc495a0Sdyoung }
853cfc495a0Sdyoung }
854cfc495a0Sdyoung ppath_release(op);
855cfc495a0Sdyoung }
856cfc495a0Sdyoung return rsrcs;
857cfc495a0Sdyoung }
858cfc495a0Sdyoung
859cfc495a0Sdyoung void
pci_ranges_infer(pci_chipset_tag_t pc,int minbus,int maxbus,bus_addr_t * iobasep,bus_size_t * iosizep,bus_addr_t * membasep,bus_size_t * memsizep)860cfc495a0Sdyoung pci_ranges_infer(pci_chipset_tag_t pc, int minbus, int maxbus,
861cfc495a0Sdyoung bus_addr_t *iobasep, bus_size_t *iosizep,
862cfc495a0Sdyoung bus_addr_t *membasep, bus_size_t *memsizep)
863cfc495a0Sdyoung {
864cfc495a0Sdyoung prop_dictionary_t iodict = NULL, memdict = NULL;
865cfc495a0Sdyoung prop_array_t iorsvns, memrsvns;
866cfc495a0Sdyoung struct range_infer_ctx ric = {
867cfc495a0Sdyoung .ric_io_bottom = ~((bus_addr_t)0)
868cfc495a0Sdyoung , .ric_io_top = 0
869cfc495a0Sdyoung , .ric_mmio_bottom = ~((bus_addr_t)0)
870cfc495a0Sdyoung , .ric_mmio_top = 0
871cfc495a0Sdyoung , .ric_pals = TAILQ_HEAD_INITIALIZER(ric.ric_pals)
872cfc495a0Sdyoung };
873cfc495a0Sdyoung const pci_alloc_t *pal;
874cfc495a0Sdyoung
875cfc495a0Sdyoung ric.ric_pc = pc;
876cfc495a0Sdyoung pci_device_foreach_min(pc, minbus, maxbus, mmio_range_infer, &ric);
877cfc495a0Sdyoung pci_device_foreach_min(pc, minbus, maxbus, io_range_infer, &ric);
878cfc495a0Sdyoung if (membasep != NULL)
879cfc495a0Sdyoung *membasep = ric.ric_mmio_bottom;
880cfc495a0Sdyoung if (memsizep != NULL)
881cfc495a0Sdyoung *memsizep = ric.ric_mmio_top - ric.ric_mmio_bottom;
882cfc495a0Sdyoung if (iobasep != NULL)
883cfc495a0Sdyoung *iobasep = ric.ric_io_bottom;
884cfc495a0Sdyoung if (iosizep != NULL)
885cfc495a0Sdyoung *iosizep = ric.ric_io_top - ric.ric_io_bottom;
886cfc495a0Sdyoung aprint_verbose("%s: inferred %" PRIuMAX
887cfc495a0Sdyoung " bytes of memory-mapped PCI space at 0x%" PRIxMAX "\n", __func__,
888cfc495a0Sdyoung (uintmax_t)(ric.ric_mmio_top - ric.ric_mmio_bottom),
889cfc495a0Sdyoung (uintmax_t)ric.ric_mmio_bottom);
890cfc495a0Sdyoung aprint_verbose("%s: inferred %" PRIuMAX
891cfc495a0Sdyoung " bytes of PCI I/O space at 0x%" PRIxMAX "\n", __func__,
892cfc495a0Sdyoung (uintmax_t)(ric.ric_io_top - ric.ric_io_bottom),
893cfc495a0Sdyoung (uintmax_t)ric.ric_io_bottom);
894cfc495a0Sdyoung TAILQ_FOREACH(pal, &ric.ric_pals, pal_link)
895cfc495a0Sdyoung pci_alloc_print(pc, pal);
896cfc495a0Sdyoung
897cfc495a0Sdyoung if ((memdict = prop_dictionary_create()) == NULL) {
898cfc495a0Sdyoung aprint_error("%s: could not create PCI MMIO "
899cfc495a0Sdyoung "resources dictionary\n", __func__);
900cfc495a0Sdyoung } else if ((memrsvns = prop_array_create()) == NULL) {
901cfc495a0Sdyoung aprint_error("%s: could not create PCI BIOS memory "
902cfc495a0Sdyoung "reservations array\n", __func__);
903cfc495a0Sdyoung } else if (!prop_dictionary_set(memdict, "bios-reservations",
904cfc495a0Sdyoung memrsvns)) {
905cfc495a0Sdyoung aprint_error("%s: could not record PCI BIOS memory "
906cfc495a0Sdyoung "reservations array\n", __func__);
907cfc495a0Sdyoung } else if (!pci_range_record(pc, memrsvns, &ric.ric_pals,
908cfc495a0Sdyoung PCI_ALLOC_SPACE_MEM)) {
909cfc495a0Sdyoung aprint_error("%s: could not record PCI BIOS memory "
910cfc495a0Sdyoung "reservations\n", __func__);
911cfc495a0Sdyoung } else if (!prop_dictionary_set_uint64(memdict,
912cfc495a0Sdyoung "start", ric.ric_mmio_bottom) ||
913cfc495a0Sdyoung !prop_dictionary_set_uint64(memdict, "size",
914cfc495a0Sdyoung ric.ric_mmio_top - ric.ric_mmio_bottom)) {
915cfc495a0Sdyoung aprint_error("%s: could not record PCI memory min & max\n",
916cfc495a0Sdyoung __func__);
917cfc495a0Sdyoung } else if ((iodict = prop_dictionary_create()) == NULL) {
918cfc495a0Sdyoung aprint_error("%s: could not create PCI I/O "
919cfc495a0Sdyoung "resources dictionary\n", __func__);
920cfc495a0Sdyoung } else if ((iorsvns = prop_array_create()) == NULL) {
921cfc495a0Sdyoung aprint_error("%s: could not create PCI BIOS I/O "
922cfc495a0Sdyoung "reservations array\n", __func__);
923cfc495a0Sdyoung } else if (!prop_dictionary_set(iodict, "bios-reservations",
924cfc495a0Sdyoung iorsvns)) {
925cfc495a0Sdyoung aprint_error("%s: could not record PCI BIOS I/O "
926cfc495a0Sdyoung "reservations array\n", __func__);
927cfc495a0Sdyoung } else if (!pci_range_record(pc, iorsvns, &ric.ric_pals,
928cfc495a0Sdyoung PCI_ALLOC_SPACE_IO)) {
929cfc495a0Sdyoung aprint_error("%s: could not record PCI BIOS I/O "
930cfc495a0Sdyoung "reservations\n", __func__);
931cfc495a0Sdyoung } else if (!prop_dictionary_set_uint64(iodict,
932cfc495a0Sdyoung "start", ric.ric_io_bottom) ||
933cfc495a0Sdyoung !prop_dictionary_set_uint64(iodict, "size",
934cfc495a0Sdyoung ric.ric_io_top - ric.ric_io_bottom)) {
935cfc495a0Sdyoung aprint_error("%s: could not record PCI I/O min & max\n",
936cfc495a0Sdyoung __func__);
937cfc495a0Sdyoung } else if ((pci_rsrc_dict = prop_dictionary_create()) == NULL) {
938cfc495a0Sdyoung aprint_error("%s: could not create PCI resources dictionary\n",
939cfc495a0Sdyoung __func__);
940cfc495a0Sdyoung } else if (!prop_dictionary_set(pci_rsrc_dict, "memory", memdict) ||
941cfc495a0Sdyoung !prop_dictionary_set(pci_rsrc_dict, "io", iodict)) {
942cfc495a0Sdyoung aprint_error("%s: could not record PCI memory- or I/O-"
943cfc495a0Sdyoung "resources dictionary\n", __func__);
944cfc495a0Sdyoung prop_object_release(pci_rsrc_dict);
945cfc495a0Sdyoung pci_rsrc_dict = NULL;
946cfc495a0Sdyoung }
947cfc495a0Sdyoung
948cfc495a0Sdyoung if (iodict != NULL)
949cfc495a0Sdyoung prop_object_release(iodict);
950cfc495a0Sdyoung if (memdict != NULL)
951cfc495a0Sdyoung prop_object_release(memdict);
952cfc495a0Sdyoung /* XXX release iorsvns, memrsvns */
953cfc495a0Sdyoung }
9548295eb1bSdyoung
9558295eb1bSdyoung static bool
pcibus_rsvn_predicate(void * arg,prop_dictionary_t rsvn)9568295eb1bSdyoung pcibus_rsvn_predicate(void *arg, prop_dictionary_t rsvn)
9578295eb1bSdyoung {
9588295eb1bSdyoung struct pcibus_attach_args *pba = arg;
9598295eb1bSdyoung uint8_t bus;
9608295eb1bSdyoung
9618295eb1bSdyoung if (!prop_dictionary_get_uint8(rsvn, "bus", &bus))
9628295eb1bSdyoung return false;
9638295eb1bSdyoung
9648295eb1bSdyoung return pba->pba_bus <= bus && bus <= pba->pba_sub;
9658295eb1bSdyoung }
9668295eb1bSdyoung
9678295eb1bSdyoung static bool
pci_rsvn_predicate(void * arg,prop_dictionary_t rsvn)9688295eb1bSdyoung pci_rsvn_predicate(void *arg, prop_dictionary_t rsvn)
9698295eb1bSdyoung {
9708295eb1bSdyoung struct pci_attach_args *pa = arg;
9718295eb1bSdyoung uint8_t bus, device, function;
9728295eb1bSdyoung bool rc;
9738295eb1bSdyoung
9748295eb1bSdyoung rc = prop_dictionary_get_uint8(rsvn, "bus", &bus) &&
9758295eb1bSdyoung prop_dictionary_get_uint8(rsvn, "device", &device) &&
9768295eb1bSdyoung prop_dictionary_get_uint8(rsvn, "function", &function);
9778295eb1bSdyoung
9788295eb1bSdyoung if (!rc)
9798295eb1bSdyoung return false;
9808295eb1bSdyoung
9818295eb1bSdyoung return pa->pa_bus == bus && pa->pa_device == device &&
9828295eb1bSdyoung pa->pa_function == function;
9838295eb1bSdyoung }
9848295eb1bSdyoung
9858295eb1bSdyoung void
device_pci_props_register(device_t dev,void * aux)9868295eb1bSdyoung device_pci_props_register(device_t dev, void *aux)
9878295eb1bSdyoung {
9888295eb1bSdyoung cfdata_t cf;
9898295eb1bSdyoung prop_dictionary_t dict;
9908295eb1bSdyoung
9918295eb1bSdyoung cf = (device_parent(dev) != NULL) ? device_cfdata(dev) : NULL;
9928295eb1bSdyoung #if 0
9938295eb1bSdyoung aprint_normal_dev(dev, "is%s a pci, parent %p, cf %p, ifattr %s\n",
9948295eb1bSdyoung device_is_a(dev, "pci") ? "" : " not",
995cbab9cadSchs device_parent(dev),
9968295eb1bSdyoung cf,
9978295eb1bSdyoung cf != NULL ? cfdata_ifattr(cf) : "");
9988295eb1bSdyoung #endif
9998295eb1bSdyoung if (pci_rsrc_dict == NULL)
10008295eb1bSdyoung return;
10018295eb1bSdyoung
10028295eb1bSdyoung if (!device_is_a(dev, "pci") &&
10038295eb1bSdyoung (cf == NULL || strcmp(cfdata_ifattr(cf), "pci") != 0))
10048295eb1bSdyoung return;
10058295eb1bSdyoung
10068295eb1bSdyoung dict = pci_rsrc_filter(pci_rsrc_dict,
10078295eb1bSdyoung device_is_a(dev, "pci") ? &pcibus_rsvn_predicate
10088295eb1bSdyoung : &pci_rsvn_predicate, aux);
10098295eb1bSdyoung if (dict == NULL)
10108295eb1bSdyoung return;
10118295eb1bSdyoung (void)prop_dictionary_set(device_properties(dev),
10128295eb1bSdyoung "pci-resources", dict);
10138295eb1bSdyoung }
1014