Sun Aug 28 06:04:18 2011 UTC ()
Add some code for grovelling in the PCI configuration space for all
of the memory & I/O space reserved by the PCI BIOS for PCI devices
(including bridges) and recording that information for later use.

The code takes between 13k and 50k (depends on the architecture and,
bizarrely, the kernel configuration) so I am going to move it from
pci_machdep.c into its own module on Monday.


(dyoung)
diff -r1.7 -r1.8 src/sys/arch/x86/include/pci_machdep_common.h
diff -r1.47 -r1.48 src/sys/arch/x86/pci/pci_machdep.c

cvs diff -r1.7 -r1.8 src/sys/arch/x86/include/pci_machdep_common.h (expand / switch to unified diff)

--- src/sys/arch/x86/include/pci_machdep_common.h 2011/08/01 11:08:03 1.7
+++ src/sys/arch/x86/include/pci_machdep_common.h 2011/08/28 06:04:17 1.8
@@ -1,14 +1,14 @@ @@ -1,14 +1,14 @@
1/* $NetBSD: pci_machdep_common.h,v 1.7 2011/08/01 11:08:03 drochner Exp $ */ 1/* $NetBSD: pci_machdep_common.h,v 1.8 2011/08/28 06:04:17 dyoung Exp $ */
2 2
3/* 3/*
4 * Copyright (c) 1996 Christopher G. Demetriou. All rights reserved. 4 * Copyright (c) 1996 Christopher G. Demetriou. All rights reserved.
5 * Copyright (c) 1994 Charles M. Hannum. All rights reserved. 5 * Copyright (c) 1994 Charles M. Hannum. All rights reserved.
6 * 6 *
7 * Redistribution and use in source and binary forms, with or without 7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions 8 * modification, are permitted provided that the following conditions
9 * are met: 9 * are met:
10 * 1. Redistributions of source code must retain the above copyright 10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer. 11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright 12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the 13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution. 14 * documentation and/or other materials provided with the distribution.
@@ -130,17 +130,21 @@ int pchb_get_bus_number(pci_chipset_tag @@ -130,17 +130,21 @@ int pchb_get_bus_number(pci_chipset_tag
130#define X86_PCI_INTERRUPT_LINE_NO_CONNECTION 0xff 130#define X86_PCI_INTERRUPT_LINE_NO_CONNECTION 0xff
131 131
132void pci_device_foreach(pci_chipset_tag_t, int, 132void pci_device_foreach(pci_chipset_tag_t, int,
133 void (*)(pci_chipset_tag_t, pcitag_t, void*), 133 void (*)(pci_chipset_tag_t, pcitag_t, void*),
134 void *); 134 void *);
135  135
136void pci_device_foreach_min(pci_chipset_tag_t, int, int, 136void pci_device_foreach_min(pci_chipset_tag_t, int, int,
137 void (*)(pci_chipset_tag_t, pcitag_t, void*), 137 void (*)(pci_chipset_tag_t, pcitag_t, void*),
138 void *); 138 void *);
139  139
140void pci_bridge_foreach(pci_chipset_tag_t, int, int, 140void pci_bridge_foreach(pci_chipset_tag_t, int, int,
141 void (*) (pci_chipset_tag_t, pcitag_t, void *), void *); 141 void (*) (pci_chipset_tag_t, pcitag_t, void *), void *);
142 142
143void pci_mmio_range_infer(pci_chipset_tag_t, int, int, bus_addr_t *, 143void pci_ranges_infer(pci_chipset_tag_t, int, int, bus_addr_t *,
144 bus_size_t *); 144 bus_size_t *, bus_addr_t *, bus_size_t *);
 145
 146extern prop_dictionary_t pci_rsrc_dict;
 147prop_dictionary_t pci_rsrc_filter(prop_dictionary_t,
 148 bool (*)(void *, prop_dictionary_t), void *arg);
145 149
146#endif /* _X86_PCI_MACHDEP_COMMON_H_ */ 150#endif /* _X86_PCI_MACHDEP_COMMON_H_ */

cvs diff -r1.47 -r1.48 src/sys/arch/x86/pci/pci_machdep.c (expand / switch to unified diff)

--- src/sys/arch/x86/pci/pci_machdep.c 2011/08/28 04:59:37 1.47
+++ src/sys/arch/x86/pci/pci_machdep.c 2011/08/28 06:04:18 1.48
@@ -1,14 +1,14 @@ @@ -1,14 +1,14 @@
1/* $NetBSD: pci_machdep.c,v 1.47 2011/08/28 04:59:37 dyoung Exp $ */ 1/* $NetBSD: pci_machdep.c,v 1.48 2011/08/28 06:04:18 dyoung Exp $ */
2 2
3/*- 3/*-
4 * Copyright (c) 1997, 1998 The NetBSD Foundation, Inc. 4 * Copyright (c) 1997, 1998 The NetBSD Foundation, Inc.
5 * All rights reserved. 5 * All rights reserved.
6 * 6 *
7 * This code is derived from software contributed to The NetBSD Foundation 7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility, 8 * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
9 * NASA Ames Research Center. 9 * NASA Ames Research Center.
10 * 10 *
11 * Redistribution and use in source and binary forms, with or without 11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions 12 * modification, are permitted provided that the following conditions
13 * are met: 13 * are met:
14 * 1. Redistributions of source code must retain the above copyright 14 * 1. Redistributions of source code must retain the above copyright
@@ -63,38 +63,41 @@ @@ -63,38 +63,41 @@
63/* 63/*
64 * Machine-specific functions for PCI autoconfiguration. 64 * Machine-specific functions for PCI autoconfiguration.
65 * 65 *
66 * On PCs, there are two methods of generating PCI configuration cycles. 66 * On PCs, there are two methods of generating PCI configuration cycles.
67 * We try to detect the appropriate mechanism for this machine and set 67 * We try to detect the appropriate mechanism for this machine and set
68 * up a few function pointers to access the correct method directly. 68 * up a few function pointers to access the correct method directly.
69 * 69 *
70 * The configuration method can be hard-coded in the config file by 70 * The configuration method can be hard-coded in the config file by
71 * using `options PCI_CONF_MODE=N', where `N' is the configuration mode 71 * using `options PCI_CONF_MODE=N', where `N' is the configuration mode
72 * as defined section 3.6.4.1, `Generating Configuration Cycles'. 72 * as defined section 3.6.4.1, `Generating Configuration Cycles'.
73 */ 73 */
74 74
75#include <sys/cdefs.h> 75#include <sys/cdefs.h>
76__KERNEL_RCSID(0, "$NetBSD: pci_machdep.c,v 1.47 2011/08/28 04:59:37 dyoung Exp $"); 76__KERNEL_RCSID(0, "$NetBSD: pci_machdep.c,v 1.48 2011/08/28 06:04:18 dyoung Exp $");
77 77
78#include <sys/types.h> 78#include <sys/types.h>
79#include <sys/param.h> 79#include <sys/param.h>
80#include <sys/time.h> 80#include <sys/time.h>
81#include <sys/systm.h> 81#include <sys/systm.h>
82#include <sys/errno.h> 82#include <sys/errno.h>
83#include <sys/device.h> 83#include <sys/device.h>
84#include <sys/bus.h> 84#include <sys/bus.h>
85#include <sys/cpu.h> 85#include <sys/cpu.h>
86#include <sys/kmem.h> 86#include <sys/kmem.h>
87 87
 88#include <prop/proplib.h>
 89#include <ppath/ppath.h>
 90
88#include <uvm/uvm_extern.h> 91#include <uvm/uvm_extern.h>
89 92
90#include <machine/bus_private.h> 93#include <machine/bus_private.h>
91 94
92#include <machine/pio.h> 95#include <machine/pio.h>
93#include <machine/lock.h> 96#include <machine/lock.h>
94 97
95#include <dev/isa/isareg.h> 98#include <dev/isa/isareg.h>
96#include <dev/isa/isavar.h> 99#include <dev/isa/isavar.h>
97#include <dev/pci/pcivar.h> 100#include <dev/pci/pcivar.h>
98#include <dev/pci/pcireg.h> 101#include <dev/pci/pcireg.h>
99#include <dev/pci/pccbbreg.h> 102#include <dev/pci/pccbbreg.h>
100#include <dev/pci/pcidevs.h> 103#include <dev/pci/pcidevs.h>
@@ -740,26 +743,938 @@ pci_device_foreach_min(pci_chipset_tag_t @@ -740,26 +743,938 @@ pci_device_foreach_min(pci_chipset_tag_t
740void 743void
741pci_bridge_foreach(pci_chipset_tag_t pc, int minbus, int maxbus, 744pci_bridge_foreach(pci_chipset_tag_t pc, int minbus, int maxbus,
742 void (*func)(pci_chipset_tag_t, pcitag_t, void *), void *ctx) 745 void (*func)(pci_chipset_tag_t, pcitag_t, void *), void *ctx)
743{ 746{
744 struct pci_bridge_hook_arg bridge_hook; 747 struct pci_bridge_hook_arg bridge_hook;
745 748
746 bridge_hook.func = func; 749 bridge_hook.func = func;
747 bridge_hook.arg = ctx;  750 bridge_hook.arg = ctx;
748 751
749 pci_device_foreach_min(pc, minbus, maxbus, pci_bridge_hook, 752 pci_device_foreach_min(pc, minbus, maxbus, pci_bridge_hook,
750 &bridge_hook);  753 &bridge_hook);
751} 754}
752 755
 756typedef enum pci_alloc_regtype {
 757 PCI_ALLOC_REGTYPE_NONE = 0
 758 , PCI_ALLOC_REGTYPE_BAR = 1
 759 , PCI_ALLOC_REGTYPE_WIN = 2
 760 , PCI_ALLOC_REGTYPE_CBWIN = 3
 761 , PCI_ALLOC_REGTYPE_VGA_EN = 4
 762} pci_alloc_regtype_t;
 763
 764typedef enum pci_alloc_space {
 765 PCI_ALLOC_SPACE_IO = 0
 766 , PCI_ALLOC_SPACE_MEM = 1
 767} pci_alloc_space_t;
 768
 769typedef enum pci_alloc_flags {
 770 PCI_ALLOC_F_PREFETCHABLE = 0x1
 771} pci_alloc_flags_t;
 772
 773typedef struct pci_alloc {
 774 TAILQ_ENTRY(pci_alloc) pal_link;
 775 pcitag_t pal_tag;
 776 uint64_t pal_addr;
 777 uint64_t pal_size;
 778 pci_alloc_regtype_t pal_type;
 779 struct pci_alloc_reg {
 780 int r_ofs;
 781 pcireg_t r_val;
 782 pcireg_t r_mask;
 783 } pal_reg[3];
 784 pci_alloc_space_t pal_space;
 785 pci_alloc_flags_t pal_flags;
 786} pci_alloc_t;
 787
 788typedef struct pci_alloc_reg pci_alloc_reg_t;
 789
 790TAILQ_HEAD(pci_alloc_list, pci_alloc);
 791
 792typedef struct pci_alloc_list pci_alloc_list_t;
 793
 794static pci_alloc_t *
 795pci_alloc_dup(const pci_alloc_t *pal)
 796{
 797 pci_alloc_t *npal;
 798
 799 if ((npal = kmem_alloc(sizeof(*npal), KM_SLEEP)) == NULL)
 800 return NULL;
 801
 802 *npal = *pal;
 803
 804 return npal;
 805}
 806
 807static bool
 808pci_alloc_linkdup(pci_alloc_list_t *pals, const pci_alloc_t *pal)
 809{
 810 pci_alloc_t *npal;
 811
 812 if ((npal = pci_alloc_dup(pal)) == NULL)
 813 return false;
 814
 815 TAILQ_INSERT_TAIL(pals, npal, pal_link);
 816
 817 return true;
 818}
 819
 820struct range_infer_ctx {
 821 pci_chipset_tag_t ric_pc;
 822 pci_alloc_list_t ric_pals;
 823 bus_addr_t ric_mmio_bottom;
 824 bus_addr_t ric_mmio_top;
 825 bus_addr_t ric_io_bottom;
 826 bus_addr_t ric_io_top;
 827};
 828
 829#if 1
 830static bool
 831io_range_extend(struct range_infer_ctx *ric, const pci_alloc_t *pal)
 832{
 833 if (ric->ric_io_bottom > pal->pal_addr)
 834 ric->ric_io_bottom = pal->pal_addr;
 835 if (ric->ric_io_top < pal->pal_addr + pal->pal_size)
 836 ric->ric_io_top = pal->pal_addr + pal->pal_size;
 837
 838 return pci_alloc_linkdup(&ric->ric_pals, pal);
 839}
 840
 841static bool
 842io_range_extend_by_bar(struct range_infer_ctx *ric, int bus, int dev, int fun,
 843 int ofs, pcireg_t curbar, pcireg_t sizebar)
 844{
 845 pci_alloc_reg_t *r;
 846 pci_alloc_t pal = {
 847 .pal_flags = 0
 848 , .pal_space = PCI_ALLOC_SPACE_IO
 849 , .pal_type = PCI_ALLOC_REGTYPE_BAR
 850 , .pal_reg = {{
 851 .r_mask = ~(pcireg_t)0
 852 }}
 853 };
 854
 855 r = &pal.pal_reg[0];
 856
 857 pal.pal_tag = pci_make_tag(ric->ric_pc, bus, dev, fun);
 858 r->r_ofs = ofs;
 859 r->r_val = curbar;
 860
 861 pal.pal_addr = PCI_MAPREG_IO_ADDR(curbar);
 862 pal.pal_size = PCI_MAPREG_IO_SIZE(sizebar);
 863
 864 aprint_debug("%s: %d.%d.%d base at %" PRIx64 " size %" PRIx64 "\n",
 865 __func__, bus, dev, fun, pal.pal_addr, pal.pal_size);
 866
 867 return (pal.pal_size == 0) || io_range_extend(ric, &pal);
 868}
 869
 870static bool
 871io_range_extend_by_vga_enable(struct range_infer_ctx *ric,
 872 int bus, int dev, int fun, pcireg_t csr, pcireg_t bcr)
 873{
 874 pci_alloc_reg_t *r;
 875 pci_alloc_t tpal = {
 876 .pal_flags = 0
 877 , .pal_space = PCI_ALLOC_SPACE_IO
 878 , .pal_type = PCI_ALLOC_REGTYPE_VGA_EN
 879 , .pal_reg = {{
 880 .r_ofs = PCI_COMMAND_STATUS_REG
 881 , .r_mask = PCI_COMMAND_IO_ENABLE
 882 }, {
 883 .r_ofs = PCI_BRIDGE_CONTROL_REG
 884 , .r_mask =
 885 PCI_BRIDGE_CONTROL_VGA << PCI_BRIDGE_CONTROL_SHIFT
 886 }}
 887 }, pal[2];
 888
 889 aprint_debug("%s: %d.%d.%d enter\n", __func__, bus, dev, fun);
 890
 891 if ((csr & PCI_COMMAND_IO_ENABLE) == 0 ||
 892 (bcr & (PCI_BRIDGE_CONTROL_VGA << PCI_BRIDGE_CONTROL_SHIFT)) == 0) {
 893 aprint_debug("%s: %d.%d.%d I/O or VGA disabled\n",
 894 __func__, bus, dev, fun);
 895 return true;
 896 }
 897
 898 r = &tpal.pal_reg[0];
 899 tpal.pal_tag = pci_make_tag(ric->ric_pc, bus, dev, fun);
 900 r[0].r_val = csr;
 901 r[1].r_val = bcr;
 902
 903 pal[0] = pal[1] = tpal;
 904
 905 pal[0].pal_addr = 0x3b0;
 906 pal[0].pal_size = 0x3bb - 0x3b0 + 1;
 907
 908 pal[1].pal_addr = 0x3c0;
 909 pal[1].pal_size = 0x3df - 0x3c0 + 1;
 910
 911 /* XXX add aliases for pal[0..1] */
 912
 913 return io_range_extend(ric, &pal[0]) && io_range_extend(ric, &pal[1]);
 914}
 915
 916static bool
 917io_range_extend_by_win(struct range_infer_ctx *ric,
 918 int bus, int dev, int fun, int ofs, int ofshigh,
 919 pcireg_t io, pcireg_t iohigh)
 920{
 921 const int fourkb = 4 * 1024;
 922 pcireg_t baser, limitr;
 923 pci_alloc_reg_t *r;
 924 pci_alloc_t pal = {
 925 .pal_flags = 0
 926 , .pal_space = PCI_ALLOC_SPACE_IO
 927 , .pal_type = PCI_ALLOC_REGTYPE_WIN
 928 , .pal_reg = {{
 929 .r_mask = ~(pcireg_t)0
 930 }}
 931 };
 932
 933 r = &pal.pal_reg[0];
 934
 935 pal.pal_tag = pci_make_tag(ric->ric_pc, bus, dev, fun);
 936 r[0].r_ofs = ofs;
 937 r[0].r_val = io;
 938
 939 baser = ((io >> PCI_BRIDGE_STATIO_IOBASE_SHIFT) &
 940 PCI_BRIDGE_STATIO_IOBASE_MASK) >> 4;
 941 limitr = ((io >> PCI_BRIDGE_STATIO_IOLIMIT_SHIFT) &
 942 PCI_BRIDGE_STATIO_IOLIMIT_MASK) >> 4;
 943
 944 if (PCI_BRIDGE_IO_32BITS(io)) {
 945 pcireg_t baseh, limith;
 946
 947 r[1].r_mask = ~(pcireg_t)0;
 948 r[1].r_ofs = ofshigh;
 949 r[1].r_val = iohigh;
 950
 951 baseh = (iohigh >> PCI_BRIDGE_IOHIGH_BASE_SHIFT) & PCI_BRIDGE_IOHIGH_BASE_MASK;
 952 limith = (iohigh >> PCI_BRIDGE_IOHIGH_LIMIT_SHIFT) & PCI_BRIDGE_IOHIGH_LIMIT_MASK;
 953
 954 baser |= baseh << 4;
 955 limitr |= limith << 4;
 956 }
 957
 958 /* XXX check with the PCI standard */
 959 if (baser > limitr)
 960 return true;
 961
 962 pal.pal_addr = baser * fourkb;
 963 pal.pal_size = (limitr - baser + 1) * fourkb;
 964
 965 aprint_debug("%s: %d.%d.%d window at %" PRIx64 " size %" PRIx64 "\n",
 966 __func__, bus, dev, fun, pal.pal_addr, pal.pal_size);
 967
 968 return io_range_extend(ric, &pal);
 969}
 970
 971static bool
 972io_range_extend_by_cbwin(struct range_infer_ctx *ric,
 973 int bus, int dev, int fun, int ofs, pcireg_t base0, pcireg_t limit0)
 974{
 975 pcireg_t base, limit;
 976 pci_alloc_reg_t *r;
 977 pci_alloc_t pal = {
 978 .pal_flags = 0
 979 , .pal_space = PCI_ALLOC_SPACE_IO
 980 , .pal_type = PCI_ALLOC_REGTYPE_CBWIN
 981 , .pal_reg = {{
 982 .r_mask = ~(pcireg_t)0
 983 }, {
 984 .r_mask = ~(pcireg_t)0
 985 }}
 986 };
 987
 988 r = &pal.pal_reg[0];
 989
 990 pal.pal_tag = pci_make_tag(ric->ric_pc, bus, dev, fun);
 991 r[0].r_ofs = ofs;
 992 r[0].r_val = base0;
 993 r[1].r_ofs = ofs + 4;
 994 r[1].r_val = limit0;
 995
 996 base = base0 & __BITS(31, 2);
 997 limit = limit0 & __BITS(31, 2);
 998
 999 if (base > limit)
 1000 return true;
 1001
 1002 pal.pal_addr = base;
 1003 pal.pal_size = limit - base + 4; /* XXX */
 1004
 1005 aprint_debug("%s: %d.%d.%d window at %" PRIx64 " size %" PRIx64 "\n",
 1006 __func__, bus, dev, fun, pal.pal_addr, pal.pal_size);
 1007
 1008 return io_range_extend(ric, &pal);
 1009}
 1010
 1011static void
 1012io_range_infer(pci_chipset_tag_t pc, pcitag_t tag, void *ctx)
 1013{
 1014 struct range_infer_ctx *ric = ctx;
 1015 pcireg_t bhlcr, limit, io;
 1016 int bar, bus, dev, fun, hdrtype, nbar;
 1017 bool ok = true;
 1018
 1019 bhlcr = pci_conf_read(pc, tag, PCI_BHLC_REG);
 1020
 1021 hdrtype = PCI_HDRTYPE_TYPE(bhlcr);
 1022
 1023 pci_decompose_tag(pc, tag, &bus, &dev, &fun);
 1024
 1025 switch (hdrtype) {
 1026 case PCI_HDRTYPE_PPB:
 1027 nbar = 2;
 1028 /* Extract I/O windows */
 1029 ok = ok && io_range_extend_by_win(ric, bus, dev, fun,
 1030 PCI_BRIDGE_STATIO_REG,
 1031 PCI_BRIDGE_IOHIGH_REG,
 1032 pci_conf_read(pc, tag, PCI_BRIDGE_STATIO_REG),
 1033 pci_conf_read(pc, tag, PCI_BRIDGE_IOHIGH_REG));
 1034 ok = ok && io_range_extend_by_vga_enable(ric, bus, dev, fun,
 1035 pci_conf_read(pc, tag, PCI_COMMAND_STATUS_REG),
 1036 pci_conf_read(pc, tag, PCI_BRIDGE_CONTROL_REG));
 1037 break;
 1038 case PCI_HDRTYPE_PCB:
 1039 /* Extract I/O windows */
 1040 io = pci_conf_read(pc, tag, PCI_CB_IOBASE0);
 1041 limit = pci_conf_read(pc, tag, PCI_CB_IOLIMIT0);
 1042 ok = ok && io_range_extend_by_cbwin(ric, bus, dev, fun,
 1043 PCI_CB_IOBASE0, io, limit);
 1044 io = pci_conf_read(pc, tag, PCI_CB_IOBASE1);
 1045 limit = pci_conf_read(pc, tag, PCI_CB_IOLIMIT1);
 1046 ok = ok && io_range_extend_by_cbwin(ric, bus, dev, fun,
 1047 PCI_CB_IOBASE1, io, limit);
 1048 nbar = 1;
 1049 break;
 1050 case PCI_HDRTYPE_DEVICE:
 1051 nbar = 6;
 1052 break;
 1053 default:
 1054 aprint_debug("%s: unknown header type %d at %d.%d.%d\n",
 1055 __func__, hdrtype, bus, dev, fun);
 1056 return;
 1057 }
 1058
 1059 for (bar = 0; bar < nbar; bar++) {
 1060 pcireg_t basebar, sizebar;
 1061
 1062 basebar = pci_conf_read(pc, tag, PCI_BAR(bar));
 1063 pci_conf_write(pc, tag, PCI_BAR(bar), 0xffffffff);
 1064 sizebar = pci_conf_read(pc, tag, PCI_BAR(bar));
 1065 pci_conf_write(pc, tag, PCI_BAR(bar), basebar);
 1066
 1067 if (sizebar == 0)
 1068 continue;
 1069 if (PCI_MAPREG_TYPE(sizebar) != PCI_MAPREG_TYPE_IO)
 1070 continue;
 1071
 1072 ok = ok && io_range_extend_by_bar(ric, bus, dev, fun,
 1073 PCI_BAR(bar), basebar, sizebar);
 1074 }
 1075 if (!ok) {
 1076 aprint_verbose("I/O range inference failed at PCI %d.%d.%d\n",
 1077 bus, dev, fun);
 1078 }
 1079}
 1080#endif
 1081
 1082static bool
 1083mmio_range_extend(struct range_infer_ctx *ric, const pci_alloc_t *pal)
 1084{
 1085 if (ric->ric_mmio_bottom > pal->pal_addr)
 1086 ric->ric_mmio_bottom = pal->pal_addr;
 1087 if (ric->ric_mmio_top < pal->pal_addr + pal->pal_size)
 1088 ric->ric_mmio_top = pal->pal_addr + pal->pal_size;
 1089
 1090 return pci_alloc_linkdup(&ric->ric_pals, pal);
 1091}
 1092
 1093static bool
 1094mmio_range_extend_by_bar(struct range_infer_ctx *ric, int bus, int dev, int fun,
 1095 int ofs, pcireg_t curbar, pcireg_t sizebar)
 1096{
 1097 int type;
 1098 bool prefetchable;
 1099 pci_alloc_reg_t *r;
 1100 pci_alloc_t pal = {
 1101 .pal_flags = 0
 1102 , .pal_space = PCI_ALLOC_SPACE_MEM
 1103 , .pal_type = PCI_ALLOC_REGTYPE_BAR
 1104 , .pal_reg = {{
 1105 .r_mask = ~(pcireg_t)0
 1106 }}
 1107 };
 1108
 1109 r = &pal.pal_reg[0];
 1110
 1111 pal.pal_tag = pci_make_tag(ric->ric_pc, bus, dev, fun);
 1112 r->r_ofs = ofs;
 1113 r->r_val = curbar;
 1114
 1115 pal.pal_addr = PCI_MAPREG_MEM_ADDR(curbar);
 1116
 1117 type = PCI_MAPREG_MEM_TYPE(curbar);
 1118 prefetchable = PCI_MAPREG_MEM_PREFETCHABLE(curbar);
 1119
 1120 if (prefetchable)
 1121 pal.pal_flags |= PCI_ALLOC_F_PREFETCHABLE;
 1122
 1123 switch (type) {
 1124 case PCI_MAPREG_MEM_TYPE_32BIT:
 1125 pal.pal_size = PCI_MAPREG_MEM_SIZE(sizebar);
 1126 break;
 1127 case PCI_MAPREG_MEM_TYPE_64BIT:
 1128 pal.pal_size = PCI_MAPREG_MEM64_SIZE(sizebar);
 1129 break;
 1130 case PCI_MAPREG_MEM_TYPE_32BIT_1M:
 1131 default:
 1132 aprint_debug("%s: ignored memory type %d at %d.%d.%d\n",
 1133 __func__, type, bus, dev, fun);
 1134 return false;
 1135 }
 1136
 1137 aprint_debug("%s: %d.%d.%d base at %" PRIx64 " size %" PRIx64 "\n",
 1138 __func__, bus, dev, fun, pal.pal_addr, pal.pal_size);
 1139
 1140 return (pal.pal_size == 0) || mmio_range_extend(ric, &pal);
 1141}
 1142
 1143static bool
 1144mmio_range_extend_by_vga_enable(struct range_infer_ctx *ric,
 1145 int bus, int dev, int fun, pcireg_t csr, pcireg_t bcr)
 1146{
 1147 pci_alloc_reg_t *r;
 1148 pci_alloc_t tpal = {
 1149 .pal_flags = PCI_ALLOC_F_PREFETCHABLE /* XXX a guess */
 1150 , .pal_space = PCI_ALLOC_SPACE_MEM
 1151 , .pal_type = PCI_ALLOC_REGTYPE_VGA_EN
 1152 , .pal_reg = {{
 1153 .r_ofs = PCI_COMMAND_STATUS_REG
 1154 , .r_mask = PCI_COMMAND_MEM_ENABLE
 1155 }, {
 1156 .r_ofs = PCI_BRIDGE_CONTROL_REG
 1157 , .r_mask =
 1158 PCI_BRIDGE_CONTROL_VGA << PCI_BRIDGE_CONTROL_SHIFT
 1159 }}
 1160 }, pal;
 1161
 1162 aprint_debug("%s: %d.%d.%d enter\n", __func__, bus, dev, fun);
 1163
 1164 if ((csr & PCI_COMMAND_MEM_ENABLE) == 0 ||
 1165 (bcr & (PCI_BRIDGE_CONTROL_VGA << PCI_BRIDGE_CONTROL_SHIFT)) == 0) {
 1166 aprint_debug("%s: %d.%d.%d memory or VGA disabled\n",
 1167 __func__, bus, dev, fun);
 1168 return true;
 1169 }
 1170
 1171 r = &tpal.pal_reg[0];
 1172 tpal.pal_tag = pci_make_tag(ric->ric_pc, bus, dev, fun);
 1173 r[0].r_val = csr;
 1174 r[1].r_val = bcr;
 1175
 1176 pal = tpal;
 1177
 1178 pal.pal_addr = 0xa0000;
 1179 pal.pal_size = 0xbffff - 0xa0000 + 1;
 1180
 1181 return mmio_range_extend(ric, &pal);
 1182}
 1183
 1184static bool
 1185mmio_range_extend_by_win(struct range_infer_ctx *ric,
 1186 int bus, int dev, int fun, int ofs, pcireg_t mem)
 1187{
 1188 const int onemeg = 1024 * 1024;
 1189 pcireg_t baser, limitr;
 1190 pci_alloc_reg_t *r;
 1191 pci_alloc_t pal = {
 1192 .pal_flags = 0
 1193 , .pal_space = PCI_ALLOC_SPACE_MEM
 1194 , .pal_type = PCI_ALLOC_REGTYPE_WIN
 1195 , .pal_reg = {{
 1196 .r_mask = ~(pcireg_t)0
 1197 }}
 1198 };
 1199
 1200 r = &pal.pal_reg[0];
 1201
 1202 pal.pal_tag = pci_make_tag(ric->ric_pc, bus, dev, fun);
 1203 r->r_ofs = ofs;
 1204 r->r_val = mem;
 1205
 1206 baser = (mem >> PCI_BRIDGE_MEMORY_BASE_SHIFT) &
 1207 PCI_BRIDGE_MEMORY_BASE_MASK;
 1208 limitr = (mem >> PCI_BRIDGE_MEMORY_LIMIT_SHIFT) &
 1209 PCI_BRIDGE_MEMORY_LIMIT_MASK;
 1210
 1211 /* XXX check with the PCI standard */
 1212 if (baser > limitr || limitr == 0)
 1213 return true;
 1214
 1215 pal.pal_addr = baser * onemeg;
 1216 pal.pal_size = (limitr - baser + 1) * onemeg;
 1217
 1218 aprint_debug("%s: %d.%d.%d window at %" PRIx64 " size %" PRIx64 "\n",
 1219 __func__, bus, dev, fun, pal.pal_addr, pal.pal_size);
 1220
 1221 return mmio_range_extend(ric, &pal);
 1222}
 1223
 1224static bool
 1225mmio_range_extend_by_prememwin(struct range_infer_ctx *ric,
 1226 int bus, int dev, int fun, int ofs, pcireg_t mem,
 1227 int hibaseofs, pcireg_t hibase,
 1228 int hilimitofs, pcireg_t hilimit)
 1229{
 1230 const int onemeg = 1024 * 1024;
 1231 uint64_t baser, limitr;
 1232 pci_alloc_reg_t *r;
 1233 pci_alloc_t pal = {
 1234 .pal_flags = PCI_ALLOC_F_PREFETCHABLE
 1235 , .pal_space = PCI_ALLOC_SPACE_MEM
 1236 , .pal_type = PCI_ALLOC_REGTYPE_WIN
 1237 , .pal_reg = {{
 1238 .r_mask = ~(pcireg_t)0
 1239 }}
 1240 };
 1241
 1242 r = &pal.pal_reg[0];
 1243
 1244 pal.pal_tag = pci_make_tag(ric->ric_pc, bus, dev, fun);
 1245 r[0].r_ofs = ofs;
 1246 r[0].r_val = mem;
 1247
 1248 baser = (mem >> PCI_BRIDGE_PREFETCHMEM_BASE_SHIFT) &
 1249 PCI_BRIDGE_PREFETCHMEM_BASE_MASK;
 1250 limitr = (mem >> PCI_BRIDGE_PREFETCHMEM_LIMIT_SHIFT) &
 1251 PCI_BRIDGE_PREFETCHMEM_LIMIT_MASK;
 1252
 1253 if (PCI_BRIDGE_PREFETCHMEM_64BITS(mem)) {
 1254 r[1].r_mask = r[2].r_mask = ~(pcireg_t)0;
 1255 r[1].r_ofs = hibaseofs;
 1256 r[1].r_val = hibase;
 1257 r[2].r_ofs = hilimitofs;
 1258 r[2].r_val = hilimit;
 1259
 1260 baser |= hibase << 12;
 1261 limitr |= hibase << 12;
 1262 }
 1263
 1264 /* XXX check with the PCI standard */
 1265 if (baser > limitr || limitr == 0)
 1266 return true;
 1267
 1268 pal.pal_addr = baser * onemeg;
 1269 pal.pal_size = (limitr - baser + 1) * onemeg;
 1270
 1271 aprint_debug("%s: %d.%d.%d window at %" PRIx64 " size %" PRIx64 "\n",
 1272 __func__, bus, dev, fun, pal.pal_addr, pal.pal_size);
 1273
 1274 return mmio_range_extend(ric, &pal);
 1275}
 1276
 1277static bool
 1278mmio_range_extend_by_cbwin(struct range_infer_ctx *ric,
 1279 int bus, int dev, int fun, int ofs, pcireg_t base, pcireg_t limit,
 1280 bool prefetchable)
 1281{
 1282 pci_alloc_reg_t *r;
 1283 pci_alloc_t pal = {
 1284 .pal_flags = 0
 1285 , .pal_space = PCI_ALLOC_SPACE_MEM
 1286 , .pal_type = PCI_ALLOC_REGTYPE_CBWIN
 1287 , .pal_reg = {{
 1288 .r_mask = ~(pcireg_t)0
 1289 }, {
 1290 .r_mask = ~(pcireg_t)0
 1291 }}
 1292 };
 1293
 1294 r = &pal.pal_reg[0];
 1295
 1296 if (prefetchable)
 1297 pal.pal_flags |= PCI_ALLOC_F_PREFETCHABLE;
 1298
 1299 pal.pal_tag = pci_make_tag(ric->ric_pc, bus, dev, fun);
 1300 r[0].r_ofs = ofs;
 1301 r[0].r_val = base;
 1302 r[1].r_ofs = ofs + 4;
 1303 r[1].r_val = limit;
 1304
 1305 if (base > limit)
 1306 return true;
 1307
 1308 if (limit == 0)
 1309 return true;
 1310
 1311 pal.pal_addr = base;
 1312 pal.pal_size = limit - base + 4096;
 1313
 1314 aprint_debug("%s: %d.%d.%d window at %" PRIx64 " size %" PRIx64 "\n",
 1315 __func__, bus, dev, fun, pal.pal_addr, pal.pal_size);
 1316
 1317 return mmio_range_extend(ric, &pal);
 1318}
 1319
 1320static void
 1321mmio_range_infer(pci_chipset_tag_t pc, pcitag_t tag, void *ctx)
 1322{
 1323 struct range_infer_ctx *ric = ctx;
 1324 pcireg_t bcr, bhlcr, limit, mem, premem, hiprebase, hiprelimit;
 1325 int bar, bus, dev, fun, hdrtype, nbar;
 1326 bool ok = true;
 1327
 1328 bhlcr = pci_conf_read(pc, tag, PCI_BHLC_REG);
 1329
 1330 hdrtype = PCI_HDRTYPE_TYPE(bhlcr);
 1331
 1332 pci_decompose_tag(pc, tag, &bus, &dev, &fun);
 1333
 1334 switch (hdrtype) {
 1335 case PCI_HDRTYPE_PPB:
 1336 nbar = 2;
 1337 /* Extract memory windows */
 1338 ok = ok && mmio_range_extend_by_win(ric, bus, dev, fun,
 1339 PCI_BRIDGE_MEMORY_REG,
 1340 pci_conf_read(pc, tag, PCI_BRIDGE_MEMORY_REG));
 1341 premem = pci_conf_read(pc, tag, PCI_BRIDGE_PREFETCHMEM_REG);
 1342 if (PCI_BRIDGE_PREFETCHMEM_64BITS(premem)) {
 1343 aprint_debug("%s: 64-bit prefetchable memory window "
 1344 "at %d.%d.%d\n", __func__, bus, dev, fun);
 1345 hiprebase = pci_conf_read(pc, tag,
 1346 PCI_BRIDGE_PREFETCHBASE32_REG);
 1347 hiprelimit = pci_conf_read(pc, tag,
 1348 PCI_BRIDGE_PREFETCHLIMIT32_REG);
 1349 } else
 1350 hiprebase = hiprelimit = 0;
 1351 ok = ok &&
 1352 mmio_range_extend_by_prememwin(ric, bus, dev, fun,
 1353 PCI_BRIDGE_PREFETCHMEM_REG, premem,
 1354 PCI_BRIDGE_PREFETCHBASE32_REG, hiprebase,
 1355 PCI_BRIDGE_PREFETCHLIMIT32_REG, hiprelimit) &&
 1356 mmio_range_extend_by_vga_enable(ric, bus, dev, fun,
 1357 pci_conf_read(pc, tag, PCI_COMMAND_STATUS_REG),
 1358 pci_conf_read(pc, tag, PCI_BRIDGE_CONTROL_REG));
 1359 break;
 1360 case PCI_HDRTYPE_PCB:
 1361 /* Extract memory windows */
 1362 bcr = pci_conf_read(pc, tag, PCI_BRIDGE_CONTROL_REG);
 1363 mem = pci_conf_read(pc, tag, PCI_CB_MEMBASE0);
 1364 limit = pci_conf_read(pc, tag, PCI_CB_MEMLIMIT0);
 1365 ok = ok && mmio_range_extend_by_cbwin(ric, bus, dev, fun,
 1366 PCI_CB_MEMBASE0, mem, limit,
 1367 (bcr & CB_BCR_PREFETCH_MEMWIN0) != 0);
 1368 mem = pci_conf_read(pc, tag, PCI_CB_MEMBASE1);
 1369 limit = pci_conf_read(pc, tag, PCI_CB_MEMLIMIT1);
 1370 ok = ok && mmio_range_extend_by_cbwin(ric, bus, dev, fun,
 1371 PCI_CB_MEMBASE1, mem, limit,
 1372 (bcr & CB_BCR_PREFETCH_MEMWIN1) != 0);
 1373 nbar = 1;
 1374 break;
 1375 case PCI_HDRTYPE_DEVICE:
 1376 nbar = 6;
 1377 break;
 1378 default:
 1379 aprint_debug("%s: unknown header type %d at %d.%d.%d\n",
 1380 __func__, hdrtype, bus, dev, fun);
 1381 return;
 1382 }
 1383
 1384 for (bar = 0; bar < nbar; bar++) {
 1385 pcireg_t basebar, sizebar;
 1386
 1387 basebar = pci_conf_read(pc, tag, PCI_BAR(bar));
 1388 pci_conf_write(pc, tag, PCI_BAR(bar), 0xffffffff);
 1389 sizebar = pci_conf_read(pc, tag, PCI_BAR(bar));
 1390 pci_conf_write(pc, tag, PCI_BAR(bar), basebar);
 1391
 1392 if (sizebar == 0)
 1393 continue;
 1394 if (PCI_MAPREG_TYPE(sizebar) != PCI_MAPREG_TYPE_MEM)
 1395 continue;
 1396
 1397 ok = ok && mmio_range_extend_by_bar(ric, bus, dev, fun,
 1398 PCI_BAR(bar), basebar, sizebar);
 1399 }
 1400 if (!ok) {
 1401 aprint_verbose("MMIO range inference failed at PCI %d.%d.%d\n",
 1402 bus, dev, fun);
 1403 }
 1404}
 1405
 1406static const char *
 1407pci_alloc_regtype_string(const pci_alloc_regtype_t t)
 1408{
 1409 switch (t) {
 1410 case PCI_ALLOC_REGTYPE_BAR:
 1411 return "bar";
 1412 case PCI_ALLOC_REGTYPE_WIN:
 1413 case PCI_ALLOC_REGTYPE_CBWIN:
 1414 return "window";
 1415 case PCI_ALLOC_REGTYPE_VGA_EN:
 1416 return "vga-enable";
 1417 default:
 1418 return "<unknown>";
 1419 }
 1420}
 1421
 1422static void
 1423pci_alloc_print(pci_chipset_tag_t pc, const pci_alloc_t *pal)
 1424{
 1425 int bus, dev, fun;
 1426 const pci_alloc_reg_t *r;
 1427
 1428 pci_decompose_tag(pc, pal->pal_tag, &bus, &dev, &fun);
 1429 r = &pal->pal_reg[0];
 1430
 1431 aprint_normal("%s range [0x%08" PRIx64 ", 0x%08" PRIx64 ")"
 1432 " at %d.%d.%d %s%s 0x%02x\n",
 1433 (pal->pal_space == PCI_ALLOC_SPACE_IO) ? "IO" : "MMIO",
 1434 pal->pal_addr, pal->pal_addr + pal->pal_size,
 1435 bus, dev, fun,
 1436 (pal->pal_flags & PCI_ALLOC_F_PREFETCHABLE) ? "prefetchable " : "",
 1437 pci_alloc_regtype_string(pal->pal_type),
 1438 r->r_ofs);
 1439}
 1440
 1441prop_dictionary_t pci_rsrc_dict = NULL;
 1442
 1443static bool
 1444pci_range_record(pci_chipset_tag_t pc, prop_array_t rsvns,
 1445 pci_alloc_list_t *pals, pci_alloc_space_t space)
 1446{
 1447 int bus, dev, fun, i;
 1448 prop_array_t regs;
 1449 prop_dictionary_t reg;
 1450 const pci_alloc_t *pal;
 1451 const pci_alloc_reg_t *r;
 1452 prop_dictionary_t rsvn;
 1453
 1454 TAILQ_FOREACH(pal, pals, pal_link) {
 1455 bool ok = true;
 1456
 1457 r = &pal->pal_reg[0];
 1458
 1459 if (pal->pal_space != space)
 1460 continue;
 1461
 1462 if ((rsvn = prop_dictionary_create()) == NULL)
 1463 return false;
 1464
 1465 if ((regs = prop_array_create()) == NULL) {
 1466 prop_object_release(rsvn);
 1467 return false;
 1468 }
 1469
 1470 if (!prop_dictionary_set(rsvn, "regs", regs)) {
 1471 prop_object_release(rsvn);
 1472 prop_object_release(regs);
 1473 return false;
 1474 }
 1475
 1476 for (i = 0; i < __arraycount(pal->pal_reg); i++) {
 1477 r = &pal->pal_reg[i];
 1478
 1479 if (r->r_mask == 0)
 1480 break;
 1481
 1482 ok = (reg = prop_dictionary_create()) != NULL;
 1483 if (!ok)
 1484 break;
 1485
 1486 ok = prop_dictionary_set_uint16(reg, "offset",
 1487 r->r_ofs) &&
 1488 prop_dictionary_set_uint32(reg, "val", r->r_val) &&
 1489 prop_dictionary_set_uint32(reg, "mask",
 1490 r->r_mask) && prop_array_add(regs, reg);
 1491 if (!ok) {
 1492 prop_object_release(reg);
 1493 break;
 1494 }
 1495 }
 1496
 1497 pci_decompose_tag(pc, pal->pal_tag, &bus, &dev, &fun);
 1498
 1499 ok = ok &&
 1500 prop_dictionary_set_cstring_nocopy(rsvn, "type",
 1501 pci_alloc_regtype_string(pal->pal_type)) &&
 1502 prop_dictionary_set_uint64(rsvn, "address",
 1503 pal->pal_addr) &&
 1504 prop_dictionary_set_uint64(rsvn, "size", pal->pal_size) &&
 1505 prop_dictionary_set_uint8(rsvn, "bus", bus) &&
 1506 prop_dictionary_set_uint8(rsvn, "device", dev) &&
 1507 prop_dictionary_set_uint8(rsvn, "function", fun) &&
 1508 prop_array_add(rsvns, rsvn);
 1509 prop_object_release(rsvn);
 1510 if (!ok)
 1511 return false;
 1512 }
 1513 return true;
 1514}
 1515
 1516prop_dictionary_t
 1517pci_rsrc_filter(prop_dictionary_t rsrcs0,
 1518 bool (*predicate)(void *, prop_dictionary_t), void *arg)
 1519{
 1520 int i, space;
 1521 prop_dictionary_t rsrcs;
 1522 prop_array_t rsvns;
 1523 ppath_t *op, *p;
 1524
 1525 if ((rsrcs = prop_dictionary_copy(rsrcs0)) == NULL)
 1526 return NULL;
 1527
 1528 for (space = 0; space < 2; space++) {
 1529 op = p = ppath_create();
 1530 p = ppath_push_key(p, (space == 0) ? "memory" : "io");
 1531 p = ppath_push_key(p, "bios-reservations");
 1532 if (p == NULL) {
 1533 ppath_release(op);
 1534 return NULL;
 1535 }
 1536 if ((rsvns = ppath_lookup(rsrcs0, p)) == NULL) {
 1537 printf("%s: reservations not found\n", __func__);
 1538 ppath_release(p);
 1539 return NULL;
 1540 }
 1541 for (i = prop_array_count(rsvns); --i >= 0; ) {
 1542 prop_dictionary_t rsvn;
 1543
 1544 if ((p = ppath_push_idx(p, i)) == NULL) {
 1545 printf("%s: ppath_push_idx\n", __func__);
 1546 ppath_release(op);
 1547 prop_object_release(rsrcs);
 1548 return NULL;
 1549 }
 1550
 1551 rsvn = ppath_lookup(rsrcs0, p);
 1552
 1553 KASSERT(rsvn != NULL);
 1554
 1555 if (!(*predicate)(arg, rsvn)) {
 1556 ppath_copydel_object((prop_object_t)rsrcs0,
 1557 (prop_object_t *)&rsrcs, p);
 1558 }
 1559
 1560 if ((p = ppath_pop(p, NULL)) == NULL) {
 1561 printf("%s: ppath_pop\n", __func__);
 1562 ppath_release(p);
 1563 prop_object_release(rsrcs);
 1564 return NULL;
 1565 }
 1566 }
 1567 ppath_release(op);
 1568 }
 1569 return rsrcs;
 1570}
 1571
 1572void
 1573pci_ranges_infer(pci_chipset_tag_t pc, int minbus, int maxbus,
 1574 bus_addr_t *iobasep, bus_size_t *iosizep,
 1575 bus_addr_t *membasep, bus_size_t *memsizep)
 1576{
 1577 prop_dictionary_t iodict = NULL, memdict = NULL;
 1578 prop_array_t iorsvns, memrsvns;
 1579 struct range_infer_ctx ric = {
 1580 .ric_io_bottom = ~((bus_addr_t)0)
 1581 , .ric_io_top = 0
 1582 , .ric_mmio_bottom = ~((bus_addr_t)0)
 1583 , .ric_mmio_top = 0
 1584 , .ric_pals = TAILQ_HEAD_INITIALIZER(ric.ric_pals)
 1585 };
 1586 const pci_alloc_t *pal;
 1587
 1588 ric.ric_pc = pc;
 1589 pci_device_foreach_min(pc, minbus, maxbus, mmio_range_infer, &ric);
 1590 pci_device_foreach_min(pc, minbus, maxbus, io_range_infer, &ric);
 1591 if (membasep != NULL)
 1592 *membasep = ric.ric_mmio_bottom;
 1593 if (memsizep != NULL)
 1594 *memsizep = ric.ric_mmio_top - ric.ric_mmio_bottom;
 1595 if (iobasep != NULL)
 1596 *iobasep = ric.ric_io_bottom;
 1597 if (iosizep != NULL)
 1598 *iosizep = ric.ric_io_top - ric.ric_io_bottom;
 1599 aprint_verbose("%s: inferred %" PRIuMAX
 1600 " bytes of memory-mapped PCI space at 0x%" PRIxMAX "\n", __func__,
 1601 (uintmax_t)(ric.ric_mmio_top - ric.ric_mmio_bottom),
 1602 (uintmax_t)ric.ric_mmio_bottom);
 1603 aprint_verbose("%s: inferred %" PRIuMAX
 1604 " bytes of PCI I/O space at 0x%" PRIxMAX "\n", __func__,
 1605 (uintmax_t)(ric.ric_io_top - ric.ric_io_bottom),
 1606 (uintmax_t)ric.ric_io_bottom);
 1607 TAILQ_FOREACH(pal, &ric.ric_pals, pal_link)
 1608 pci_alloc_print(pc, pal);
 1609
 1610 if ((memdict = prop_dictionary_create()) == NULL) {
 1611 aprint_error("%s: could not create PCI MMIO "
 1612 "resources dictionary\n", __func__);
 1613 } else if ((memrsvns = prop_array_create()) == NULL) {
 1614 aprint_error("%s: could not create PCI BIOS memory "
 1615 "reservations array\n", __func__);
 1616 } else if (!prop_dictionary_set(memdict, "bios-reservations",
 1617 memrsvns)) {
 1618 aprint_error("%s: could not record PCI BIOS memory "
 1619 "reservations array\n", __func__);
 1620 } else if (!pci_range_record(pc, memrsvns, &ric.ric_pals,
 1621 PCI_ALLOC_SPACE_MEM)) {
 1622 aprint_error("%s: could not record PCI BIOS memory "
 1623 "reservations\n", __func__);
 1624 } else if (!prop_dictionary_set_uint64(memdict,
 1625 "start", ric.ric_mmio_bottom) ||
 1626 !prop_dictionary_set_uint64(memdict, "size",
 1627 ric.ric_mmio_top - ric.ric_mmio_bottom)) {
 1628 aprint_error("%s: could not record PCI memory min & max\n",
 1629 __func__);
 1630 } else if ((iodict = prop_dictionary_create()) == NULL) {
 1631 aprint_error("%s: could not create PCI I/O "
 1632 "resources dictionary\n", __func__);
 1633 } else if ((iorsvns = prop_array_create()) == NULL) {
 1634 aprint_error("%s: could not create PCI BIOS I/O "
 1635 "reservations array\n", __func__);
 1636 } else if (!prop_dictionary_set(iodict, "bios-reservations",
 1637 iorsvns)) {
 1638 aprint_error("%s: could not record PCI BIOS I/O "
 1639 "reservations array\n", __func__);
 1640 } else if (!pci_range_record(pc, iorsvns, &ric.ric_pals,
 1641 PCI_ALLOC_SPACE_IO)) {
 1642 aprint_error("%s: could not record PCI BIOS I/O "
 1643 "reservations\n", __func__);
 1644 } else if (!prop_dictionary_set_uint64(iodict,
 1645 "start", ric.ric_io_bottom) ||
 1646 !prop_dictionary_set_uint64(iodict, "size",
 1647 ric.ric_io_top - ric.ric_io_bottom)) {
 1648 aprint_error("%s: could not record PCI I/O min & max\n",
 1649 __func__);
 1650 } else if ((pci_rsrc_dict = prop_dictionary_create()) == NULL) {
 1651 aprint_error("%s: could not create PCI resources dictionary\n",
 1652 __func__);
 1653 } else if (!prop_dictionary_set(pci_rsrc_dict, "memory", memdict) ||
 1654 !prop_dictionary_set(pci_rsrc_dict, "io", iodict)) {
 1655 aprint_error("%s: could not record PCI memory- or I/O-"
 1656 "resources dictionary\n", __func__);
 1657 prop_object_release(pci_rsrc_dict);
 1658 pci_rsrc_dict = NULL;
 1659 }
 1660
 1661 if (iodict != NULL)
 1662 prop_object_release(iodict);
 1663 if (memdict != NULL)
 1664 prop_object_release(memdict);
 1665 /* XXX release iorsvns, memrsvns */
 1666}
 1667
753static void 1668static void
754pci_bridge_hook(pci_chipset_tag_t pc, pcitag_t tag, void *ctx) 1669pci_bridge_hook(pci_chipset_tag_t pc, pcitag_t tag, void *ctx)
755{ 1670{
756 struct pci_bridge_hook_arg *bridge_hook = (void *)ctx; 1671 struct pci_bridge_hook_arg *bridge_hook = (void *)ctx;
757 pcireg_t reg; 1672 pcireg_t reg;
758 1673
759 reg = pci_conf_read(pc, tag, PCI_CLASS_REG); 1674 reg = pci_conf_read(pc, tag, PCI_CLASS_REG);
760 if (PCI_CLASS(reg) == PCI_CLASS_BRIDGE && 1675 if (PCI_CLASS(reg) == PCI_CLASS_BRIDGE &&
761 (PCI_SUBCLASS(reg) == PCI_SUBCLASS_BRIDGE_PCI || 1676 (PCI_SUBCLASS(reg) == PCI_SUBCLASS_BRIDGE_PCI ||
762 PCI_SUBCLASS(reg) == PCI_SUBCLASS_BRIDGE_CARDBUS)) { 1677 PCI_SUBCLASS(reg) == PCI_SUBCLASS_BRIDGE_CARDBUS)) {
763 (*bridge_hook->func)(pc, tag, bridge_hook->arg); 1678 (*bridge_hook->func)(pc, tag, bridge_hook->arg);
764 } 1679 }
765} 1680}