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