| @@ -1,946 +1,946 @@ | | | @@ -1,946 +1,946 @@ |
1 | /* $NetBSD: acpi_mcfg.c,v 1.22 2021/01/26 15:29:41 skrll Exp $ */ | | 1 | /* $NetBSD: acpi_mcfg.c,v 1.23 2021/01/26 15:30:05 skrll Exp $ */ |
2 | | | 2 | |
3 | /*- | | 3 | /*- |
4 | * Copyright (C) 2015 NONAKA Kimihiro <nonaka@NetBSD.org> | | 4 | * Copyright (C) 2015 NONAKA Kimihiro <nonaka@NetBSD.org> |
5 | * All rights reserved. | | 5 | * 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. |
15 | * | | 15 | * |
16 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR | | 16 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR |
17 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES | | 17 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
18 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. | | 18 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. |
19 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, | | 19 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, |
20 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT | | 20 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT |
21 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | | 21 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
22 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | | 22 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
23 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | | 23 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF | | 24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF |
25 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | | 25 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
26 | */ | | 26 | */ |
27 | | | 27 | |
28 | #include "opt_pci.h" | | 28 | #include "opt_pci.h" |
29 | | | 29 | |
30 | #include <sys/cdefs.h> | | 30 | #include <sys/cdefs.h> |
31 | __KERNEL_RCSID(0, "$NetBSD: acpi_mcfg.c,v 1.22 2021/01/26 15:29:41 skrll Exp $"); | | 31 | __KERNEL_RCSID(0, "$NetBSD: acpi_mcfg.c,v 1.23 2021/01/26 15:30:05 skrll Exp $"); |
32 | | | 32 | |
33 | #include <sys/param.h> | | 33 | #include <sys/param.h> |
34 | #include <sys/device.h> | | 34 | #include <sys/device.h> |
35 | #include <sys/kmem.h> | | 35 | #include <sys/kmem.h> |
36 | #include <sys/systm.h> | | 36 | #include <sys/systm.h> |
37 | | | 37 | |
38 | #include <dev/pci/pcireg.h> | | 38 | #include <dev/pci/pcireg.h> |
39 | #include <dev/pci/pcivar.h> | | 39 | #include <dev/pci/pcivar.h> |
40 | #include <dev/pci/pciconf.h> | | 40 | #include <dev/pci/pciconf.h> |
41 | #include <dev/pci/pcidevs.h> | | 41 | #include <dev/pci/pcidevs.h> |
42 | | | 42 | |
43 | #include <dev/acpi/acpireg.h> | | 43 | #include <dev/acpi/acpireg.h> |
44 | #include <dev/acpi/acpivar.h> | | 44 | #include <dev/acpi/acpivar.h> |
45 | #include <dev/acpi/acpi_mcfg.h> | | 45 | #include <dev/acpi/acpi_mcfg.h> |
46 | | | 46 | |
47 | #include "locators.h" | | 47 | #include "locators.h" |
48 | | | 48 | |
49 | #define _COMPONENT ACPI_RESOURCE_COMPONENT | | 49 | #define _COMPONENT ACPI_RESOURCE_COMPONENT |
50 | ACPI_MODULE_NAME ("acpi_mcfg") | | 50 | ACPI_MODULE_NAME ("acpi_mcfg") |
51 | | | 51 | |
52 | #define EXTCONF_OFFSET(d, f, r) ((((d) * 8 + (f)) * PCI_EXTCONF_SIZE) + (r)) | | 52 | #define EXTCONF_OFFSET(d, f, r) ((((d) * 8 + (f)) * PCI_EXTCONF_SIZE) + (r)) |
53 | | | 53 | |
54 | #define PCIDEV_SET_VALID(mb, d, f) ((mb)->valid_devs[(d)] |= __BIT((f))) | | 54 | #define PCIDEV_SET_VALID(mb, d, f) ((mb)->valid_devs[(d)] |= __BIT((f))) |
55 | #define PCIDEV_SET_INVALID(mb, d, f) ((mb)->valid_devs[(d)] &= ~__BIT((f))) | | 55 | #define PCIDEV_SET_INVALID(mb, d, f) ((mb)->valid_devs[(d)] &= ~__BIT((f))) |
56 | #define PCIDEV_IS_VALID(mb, d, f) ((mb)->valid_devs[(d)] & __BIT((f))) | | 56 | #define PCIDEV_IS_VALID(mb, d, f) ((mb)->valid_devs[(d)] & __BIT((f))) |
57 | | | 57 | |
58 | #define EXTCONF_SET_VALID(mb, d, f) ((mb)->valid_extconf[(d)] |= __BIT((f))) | | 58 | #define EXTCONF_SET_VALID(mb, d, f) ((mb)->valid_extconf[(d)] |= __BIT((f))) |
59 | #define EXTCONF_SET_INVALID(mb, d, f) ((mb)->valid_extconf[(d)] &= ~__BIT((f))) | | 59 | #define EXTCONF_SET_INVALID(mb, d, f) ((mb)->valid_extconf[(d)] &= ~__BIT((f))) |
60 | #define EXTCONF_IS_VALID(mb, d, f) ((mb)->valid_extconf[(d)] & __BIT((f))) | | 60 | #define EXTCONF_IS_VALID(mb, d, f) ((mb)->valid_extconf[(d)] & __BIT((f))) |
61 | | | 61 | |
62 | struct mcfg_segment { | | 62 | struct mcfg_segment { |
63 | uint64_t ms_address; /* Base address */ | | 63 | uint64_t ms_address; /* Base address */ |
64 | int ms_segment; /* Segment # */ | | 64 | int ms_segment; /* Segment # */ |
65 | int ms_bus_start; /* Start bus # */ | | 65 | int ms_bus_start; /* Start bus # */ |
66 | int ms_bus_end; /* End bus # */ | | 66 | int ms_bus_end; /* End bus # */ |
67 | bus_space_tag_t ms_bst; | | 67 | bus_space_tag_t ms_bst; |
68 | struct mcfg_bus { | | 68 | struct mcfg_bus { |
69 | bus_space_handle_t bsh[32][8]; | | 69 | bus_space_handle_t bsh[32][8]; |
70 | uint8_t valid_devs[32]; | | 70 | uint8_t valid_devs[32]; |
71 | uint8_t valid_extconf[32]; | | 71 | uint8_t valid_extconf[32]; |
72 | int valid_ndevs; | | 72 | int valid_ndevs; |
73 | pcitag_t last_probed; | | 73 | pcitag_t last_probed; |
74 | } *ms_bus; | | 74 | } *ms_bus; |
75 | }; | | 75 | }; |
76 | | | 76 | |
77 | static struct mcfg_segment *mcfg_segs; | | 77 | static struct mcfg_segment *mcfg_segs; |
78 | static int mcfg_nsegs; | | 78 | static int mcfg_nsegs; |
79 | static ACPI_TABLE_MCFG *mcfg; | | 79 | static ACPI_TABLE_MCFG *mcfg; |
80 | static int mcfg_inited; | | 80 | static int mcfg_inited; |
81 | static struct acpi_softc *acpi_sc; | | 81 | static struct acpi_softc *acpi_sc; |
82 | | | 82 | |
83 | static const struct acpimcfg_ops mcfg_default_ops = { | | 83 | static const struct acpimcfg_ops mcfg_default_ops = { |
84 | .ao_validate = acpimcfg_default_validate, | | 84 | .ao_validate = acpimcfg_default_validate, |
85 | | | 85 | |
86 | .ao_read = acpimcfg_default_read, | | 86 | .ao_read = acpimcfg_default_read, |
87 | .ao_write = acpimcfg_default_write, | | 87 | .ao_write = acpimcfg_default_write, |
88 | }; | | 88 | }; |
89 | static const struct acpimcfg_ops *mcfg_ops = &mcfg_default_ops; | | 89 | static const struct acpimcfg_ops *mcfg_ops = &mcfg_default_ops; |
90 | | | 90 | |
91 | /* | | 91 | /* |
92 | * default operations. | | 92 | * default operations. |
93 | */ | | 93 | */ |
94 | bool | | 94 | bool |
95 | acpimcfg_default_validate(uint64_t address, int bus_start, int *bus_end) | | 95 | acpimcfg_default_validate(uint64_t address, int bus_start, int *bus_end) |
96 | { | | 96 | { |
97 | | | 97 | |
98 | /* Always Ok */ | | 98 | /* Always Ok */ |
99 | return true; | | 99 | return true; |
100 | } | | 100 | } |
101 | | | 101 | |
102 | uint32_t | | 102 | uint32_t |
103 | acpimcfg_default_read(bus_space_tag_t bst, bus_space_handle_t bsh, | | 103 | acpimcfg_default_read(bus_space_tag_t bst, bus_space_handle_t bsh, |
104 | bus_addr_t addr) | | 104 | bus_addr_t addr) |
105 | { | | 105 | { |
106 | | | 106 | |
107 | return bus_space_read_4(bst, bsh, addr); | | 107 | return bus_space_read_4(bst, bsh, addr); |
108 | } | | 108 | } |
109 | | | 109 | |
110 | void | | 110 | void |
111 | acpimcfg_default_write(bus_space_tag_t bst, bus_space_handle_t bsh, | | 111 | acpimcfg_default_write(bus_space_tag_t bst, bus_space_handle_t bsh, |
112 | bus_addr_t addr, uint32_t data) | | 112 | bus_addr_t addr, uint32_t data) |
113 | { | | 113 | { |
114 | | | 114 | |
115 | bus_space_write_4(bst, bsh, addr, data); | | 115 | bus_space_write_4(bst, bsh, addr, data); |
116 | } | | 116 | } |
117 | | | 117 | |
118 | | | 118 | |
119 | /* | | 119 | /* |
120 | * Check MCFG memory region at system resource | | 120 | * Check MCFG memory region at system resource |
121 | */ | | 121 | */ |
122 | struct acpimcfg_memrange { | | 122 | struct acpimcfg_memrange { |
123 | const char *hid; | | 123 | const char *hid; |
124 | uint64_t address; | | 124 | uint64_t address; |
125 | int bus_start; | | 125 | int bus_start; |
126 | int bus_end; | | 126 | int bus_end; |
127 | bool found; | | 127 | bool found; |
128 | }; | | 128 | }; |
129 | | | 129 | |
130 | static ACPI_STATUS | | 130 | static ACPI_STATUS |
131 | acpimcfg_parse_callback(ACPI_RESOURCE *res, void *ctx) | | 131 | acpimcfg_parse_callback(ACPI_RESOURCE *res, void *ctx) |
132 | { | | 132 | { |
133 | struct acpimcfg_memrange *mr = ctx; | | 133 | struct acpimcfg_memrange *mr = ctx; |
134 | const char *type; | | 134 | const char *type; |
135 | uint64_t size, mapaddr, mapsize; | | 135 | uint64_t size, mapaddr, mapsize; |
136 | int n; | | 136 | int n; |
137 | | | 137 | |
138 | switch (res->Type) { | | 138 | switch (res->Type) { |
139 | case ACPI_RESOURCE_TYPE_FIXED_MEMORY32: | | 139 | case ACPI_RESOURCE_TYPE_FIXED_MEMORY32: |
140 | type = "FIXED_MEMORY32"; | | 140 | type = "FIXED_MEMORY32"; |
141 | mapaddr = res->Data.FixedMemory32.Address; | | 141 | mapaddr = res->Data.FixedMemory32.Address; |
142 | mapsize = res->Data.FixedMemory32.AddressLength; | | 142 | mapsize = res->Data.FixedMemory32.AddressLength; |
143 | break; | | 143 | break; |
144 | | | 144 | |
145 | case ACPI_RESOURCE_TYPE_ADDRESS32: | | 145 | case ACPI_RESOURCE_TYPE_ADDRESS32: |
146 | /* XXX Only fixed size supported for now */ | | 146 | /* XXX Only fixed size supported for now */ |
147 | if (res->Data.Address32.Address.AddressLength == 0 || | | 147 | if (res->Data.Address32.Address.AddressLength == 0 || |
148 | res->Data.Address32.ProducerConsumer != ACPI_CONSUMER) | | 148 | res->Data.Address32.ProducerConsumer != ACPI_CONSUMER) |
149 | goto out; | | 149 | goto out; |
150 | | | 150 | |
151 | if (res->Data.Address32.ResourceType != ACPI_MEMORY_RANGE) | | 151 | if (res->Data.Address32.ResourceType != ACPI_MEMORY_RANGE) |
152 | goto out; | | 152 | goto out; |
153 | | | 153 | |
154 | if (res->Data.Address32.MinAddressFixed != ACPI_ADDRESS_FIXED || | | 154 | if (res->Data.Address32.MinAddressFixed != ACPI_ADDRESS_FIXED || |
155 | res->Data.Address32.MaxAddressFixed != ACPI_ADDRESS_FIXED) | | 155 | res->Data.Address32.MaxAddressFixed != ACPI_ADDRESS_FIXED) |
156 | goto out; | | 156 | goto out; |
157 | | | 157 | |
158 | type = "ADDRESS32"; | | 158 | type = "ADDRESS32"; |
159 | mapaddr = res->Data.Address32.Address.Minimum; | | 159 | mapaddr = res->Data.Address32.Address.Minimum; |
160 | mapsize = res->Data.Address32.Address.AddressLength; | | 160 | mapsize = res->Data.Address32.Address.AddressLength; |
161 | break; | | 161 | break; |
162 | | | 162 | |
163 | #ifdef _LP64 | | 163 | #ifdef _LP64 |
164 | case ACPI_RESOURCE_TYPE_ADDRESS64: | | 164 | case ACPI_RESOURCE_TYPE_ADDRESS64: |
165 | /* XXX Only fixed size supported for now */ | | 165 | /* XXX Only fixed size supported for now */ |
166 | if (res->Data.Address64.Address.AddressLength == 0 || | | 166 | if (res->Data.Address64.Address.AddressLength == 0 || |
167 | res->Data.Address64.ProducerConsumer != ACPI_CONSUMER) | | 167 | res->Data.Address64.ProducerConsumer != ACPI_CONSUMER) |
168 | goto out; | | 168 | goto out; |
169 | | | 169 | |
170 | if (res->Data.Address64.ResourceType != ACPI_MEMORY_RANGE) | | 170 | if (res->Data.Address64.ResourceType != ACPI_MEMORY_RANGE) |
171 | goto out; | | 171 | goto out; |
172 | | | 172 | |
173 | if (res->Data.Address64.MinAddressFixed != ACPI_ADDRESS_FIXED || | | 173 | if (res->Data.Address64.MinAddressFixed != ACPI_ADDRESS_FIXED || |
174 | res->Data.Address64.MaxAddressFixed != ACPI_ADDRESS_FIXED) | | 174 | res->Data.Address64.MaxAddressFixed != ACPI_ADDRESS_FIXED) |
175 | goto out; | | 175 | goto out; |
176 | | | 176 | |
177 | type = "ADDRESS64"; | | 177 | type = "ADDRESS64"; |
178 | mapaddr = res->Data.Address64.Address.Minimum; | | 178 | mapaddr = res->Data.Address64.Address.Minimum; |
179 | mapsize = res->Data.Address64.Address.AddressLength; | | 179 | mapsize = res->Data.Address64.Address.AddressLength; |
180 | break; | | 180 | break; |
181 | #endif | | 181 | #endif |
182 | | | 182 | |
183 | default: | | 183 | default: |
184 | out: | | 184 | out: |
185 | aprint_debug_dev(acpi_sc->sc_dev, "MCFG: %s: Type=%d\n", | | 185 | aprint_debug_dev(acpi_sc->sc_dev, "MCFG: %s: Type=%d\n", |
186 | mr->hid, res->Type); | | 186 | mr->hid, res->Type); |
187 | return_ACPI_STATUS(AE_OK); | | 187 | return_ACPI_STATUS(AE_OK); |
188 | } | | 188 | } |
189 | | | 189 | |
190 | aprint_debug_dev(acpi_sc->sc_dev, "MCFG: %s: Type=%d(%s), " | | 190 | aprint_debug_dev(acpi_sc->sc_dev, "MCFG: %s: Type=%d(%s), " |
191 | "Address=0x%016" PRIx64 ", Length=0x%016" PRIx64 "\n", | | 191 | "Address=0x%016" PRIx64 ", Length=0x%016" PRIx64 "\n", |
192 | mr->hid, res->Type, type, mapaddr, mapsize); | | 192 | mr->hid, res->Type, type, mapaddr, mapsize); |
193 | | | 193 | |
194 | if (mr->address < mapaddr || mr->address >= mapaddr + mapsize) | | 194 | if (mr->address < mapaddr || mr->address >= mapaddr + mapsize) |
195 | return_ACPI_STATUS(AE_OK); | | 195 | return_ACPI_STATUS(AE_OK); |
196 | | | 196 | |
197 | size = (mr->bus_end - mr->bus_start + 1) * ACPIMCFG_SIZE_PER_BUS; | | 197 | size = (mr->bus_end - mr->bus_start + 1) * ACPIMCFG_SIZE_PER_BUS; |
198 | | | 198 | |
199 | /* full map */ | | 199 | /* full map */ |
200 | if (mr->address + size <= mapaddr + mapsize) { | | 200 | if (mr->address + size <= mapaddr + mapsize) { |
201 | mr->found = true; | | 201 | mr->found = true; |
202 | return_ACPI_STATUS(AE_CTRL_TERMINATE); | | 202 | return_ACPI_STATUS(AE_CTRL_TERMINATE); |
203 | } | | 203 | } |
204 | | | 204 | |
205 | /* partial map */ | | 205 | /* partial map */ |
206 | n = (mapsize - (mr->address - mapaddr)) / ACPIMCFG_SIZE_PER_BUS; | | 206 | n = (mapsize - (mr->address - mapaddr)) / ACPIMCFG_SIZE_PER_BUS; |
207 | /* bus_start == bus_end is not allowed. */ | | 207 | /* bus_start == bus_end is not allowed. */ |
208 | if (n > 1) { | | 208 | if (n > 1) { |
209 | mr->bus_end = mr->bus_start + n - 1; | | 209 | mr->bus_end = mr->bus_start + n - 1; |
210 | mr->found = true; | | 210 | mr->found = true; |
211 | return_ACPI_STATUS(AE_CTRL_TERMINATE); | | 211 | return_ACPI_STATUS(AE_CTRL_TERMINATE); |
212 | } | | 212 | } |
213 | | | 213 | |
214 | aprint_debug_dev(acpi_sc->sc_dev, "MCFG: bus %d-%d, " | | 214 | aprint_debug_dev(acpi_sc->sc_dev, "MCFG: bus %d-%d, " |
215 | "address 0x%016" PRIx64 ": invalid size: request 0x%016" PRIx64 | | 215 | "address 0x%016" PRIx64 ": invalid size: request 0x%016" PRIx64 |
216 | ", actual 0x%016" PRIx64 "\n", | | 216 | ", actual 0x%016" PRIx64 "\n", |
217 | mr->bus_start, mr->bus_end, mr->address, size, mapsize); | | 217 | mr->bus_start, mr->bus_end, mr->address, size, mapsize); |
218 | | | 218 | |
219 | return_ACPI_STATUS(AE_OK); | | 219 | return_ACPI_STATUS(AE_OK); |
220 | } | | 220 | } |
221 | | | 221 | |
222 | static ACPI_STATUS | | 222 | static ACPI_STATUS |
223 | acpimcfg_check_system_resource(ACPI_HANDLE handle, UINT32 level, void *ctx, | | 223 | acpimcfg_check_system_resource(ACPI_HANDLE handle, UINT32 level, void *ctx, |
224 | void **retval) | | 224 | void **retval) |
225 | { | | 225 | { |
226 | struct acpimcfg_memrange *mr = ctx; | | 226 | struct acpimcfg_memrange *mr = ctx; |
227 | ACPI_STATUS status; | | 227 | ACPI_STATUS status; |
228 | | | 228 | |
229 | status = AcpiWalkResources(handle, "_CRS", acpimcfg_parse_callback, mr); | | 229 | status = AcpiWalkResources(handle, "_CRS", acpimcfg_parse_callback, mr); |
230 | if (ACPI_FAILURE(status)) | | 230 | if (ACPI_FAILURE(status)) |
231 | return_ACPI_STATUS(status); | | 231 | return_ACPI_STATUS(status); |
232 | | | 232 | |
233 | if (mr->found) | | 233 | if (mr->found) |
234 | return_ACPI_STATUS(AE_CTRL_TERMINATE); | | 234 | return_ACPI_STATUS(AE_CTRL_TERMINATE); |
235 | | | 235 | |
236 | aprint_debug_dev(acpi_sc->sc_dev, "MCFG: %s: bus %d-%d, " | | 236 | aprint_debug_dev(acpi_sc->sc_dev, "MCFG: %s: bus %d-%d, " |
237 | "address 0x%016" PRIx64 ": no valid region\n", mr->hid, | | 237 | "address 0x%016" PRIx64 ": no valid region\n", mr->hid, |
238 | mr->bus_start, mr->bus_end, mr->address); | | 238 | mr->bus_start, mr->bus_end, mr->address); |
239 | | | 239 | |
240 | return_ACPI_STATUS(AE_OK); | | 240 | return_ACPI_STATUS(AE_OK); |
241 | } | | 241 | } |
242 | | | 242 | |
243 | static bool | | 243 | static bool |
244 | acpimcfg_find_system_resource(uint64_t address, int bus_start, int *bus_end) | | 244 | acpimcfg_find_system_resource(uint64_t address, int bus_start, int *bus_end) |
245 | { | | 245 | { |
246 | static const char *system_resource_hid[] = { | | 246 | static const char *system_resource_hid[] = { |
247 | "PNP0C01", /* System Board */ | | 247 | "PNP0C01", /* System Board */ |
248 | "PNP0C02" /* General ID for reserving resources */ | | 248 | "PNP0C02" /* General ID for reserving resources */ |
249 | }; | | 249 | }; |
250 | struct acpimcfg_memrange mr; | | 250 | struct acpimcfg_memrange mr; |
251 | ACPI_STATUS status; | | 251 | ACPI_STATUS status; |
252 | int i; | | 252 | int i; |
253 | | | 253 | |
254 | mr.address = address; | | 254 | mr.address = address; |
255 | mr.bus_start = bus_start; | | 255 | mr.bus_start = bus_start; |
256 | mr.bus_end = *bus_end; | | 256 | mr.bus_end = *bus_end; |
257 | mr.found = false; | | 257 | mr.found = false; |
258 | | | 258 | |
259 | for (i = 0; i < __arraycount(system_resource_hid); i++) { | | 259 | for (i = 0; i < __arraycount(system_resource_hid); i++) { |
260 | mr.hid = system_resource_hid[i]; | | 260 | mr.hid = system_resource_hid[i]; |
261 | status = AcpiGetDevices(__UNCONST(system_resource_hid[i]), | | 261 | status = AcpiGetDevices(__UNCONST(system_resource_hid[i]), |
262 | acpimcfg_check_system_resource, &mr, NULL); | | 262 | acpimcfg_check_system_resource, &mr, NULL); |
263 | if (ACPI_FAILURE(status)) | | 263 | if (ACPI_FAILURE(status)) |
264 | continue; | | 264 | continue; |
265 | if (mr.found) { | | 265 | if (mr.found) { |
266 | *bus_end = mr.bus_end; | | 266 | *bus_end = mr.bus_end; |
267 | return true; | | 267 | return true; |
268 | } | | 268 | } |
269 | } | | 269 | } |
270 | return false; | | 270 | return false; |
271 | } | | 271 | } |
272 | | | 272 | |
273 | | | 273 | |
274 | /* | | 274 | /* |
275 | * ACPI MCFG | | 275 | * ACPI MCFG |
276 | */ | | 276 | */ |
277 | void | | 277 | void |
278 | acpimcfg_probe(struct acpi_softc *sc) | | 278 | acpimcfg_probe(struct acpi_softc *sc) |
279 | { | | 279 | { |
280 | ACPI_MCFG_ALLOCATION *ama; | | 280 | ACPI_MCFG_ALLOCATION *ama; |
281 | ACPI_STATUS status; | | 281 | ACPI_STATUS status; |
282 | uint32_t offset; | | 282 | uint32_t offset; |
283 | int i, nsegs; | | 283 | int i, nsegs; |
284 | | | 284 | |
285 | if (acpi_sc != NULL) | | 285 | if (acpi_sc != NULL) |
286 | panic("acpi_sc != NULL"); | | 286 | panic("acpi_sc != NULL"); |
287 | acpi_sc = sc; | | 287 | acpi_sc = sc; |
288 | | | 288 | |
289 | status = AcpiGetTable(ACPI_SIG_MCFG, 0, (ACPI_TABLE_HEADER **)&mcfg); | | 289 | status = AcpiGetTable(ACPI_SIG_MCFG, 0, (ACPI_TABLE_HEADER **)&mcfg); |
290 | if (ACPI_FAILURE(status)) { | | 290 | if (ACPI_FAILURE(status)) { |
291 | mcfg = NULL; | | 291 | mcfg = NULL; |
292 | return; | | 292 | return; |
293 | } | | 293 | } |
294 | | | 294 | |
295 | nsegs = 0; | | 295 | nsegs = 0; |
296 | offset = sizeof(ACPI_TABLE_MCFG); | | 296 | offset = sizeof(ACPI_TABLE_MCFG); |
297 | ama = ACPI_ADD_PTR(ACPI_MCFG_ALLOCATION, mcfg, offset); | | 297 | ama = ACPI_ADD_PTR(ACPI_MCFG_ALLOCATION, mcfg, offset); |
298 | for (i = 0; offset + sizeof(ACPI_MCFG_ALLOCATION) <= | | 298 | for (i = 0; offset + sizeof(ACPI_MCFG_ALLOCATION) <= |
299 | mcfg->Header.Length; i++) { | | 299 | mcfg->Header.Length; i++) { |
300 | aprint_debug_dev(sc->sc_dev, | | 300 | aprint_debug_dev(sc->sc_dev, |
301 | "MCFG: segment %d, bus %d-%d, address 0x%016" PRIx64 "\n", | | 301 | "MCFG: segment %d, bus %d-%d, address 0x%016" PRIx64 "\n", |
302 | ama->PciSegment, ama->StartBusNumber, ama->EndBusNumber, | | 302 | ama->PciSegment, ama->StartBusNumber, ama->EndBusNumber, |
303 | ama->Address); | | 303 | ama->Address); |
304 | nsegs++; | | 304 | nsegs++; |
305 | offset += sizeof(ACPI_MCFG_ALLOCATION); | | 305 | offset += sizeof(ACPI_MCFG_ALLOCATION); |
306 | ama = ACPI_ADD_PTR(ACPI_MCFG_ALLOCATION, mcfg, offset); | | 306 | ama = ACPI_ADD_PTR(ACPI_MCFG_ALLOCATION, mcfg, offset); |
307 | } | | 307 | } |
308 | if (nsegs == 0) { | | 308 | if (nsegs == 0) { |
309 | mcfg = NULL; | | 309 | mcfg = NULL; |
310 | return; | | 310 | return; |
311 | } | | 311 | } |
312 | | | 312 | |
313 | mcfg_segs = kmem_zalloc(sizeof(*mcfg_segs) * nsegs, KM_SLEEP); | | 313 | mcfg_segs = kmem_zalloc(sizeof(*mcfg_segs) * nsegs, KM_SLEEP); |
314 | mcfg_nsegs = nsegs; | | 314 | mcfg_nsegs = nsegs; |
315 | } | | 315 | } |
316 | | | 316 | |
317 | int | | 317 | int |
318 | acpimcfg_init(bus_space_tag_t memt, const struct acpimcfg_ops *ops) | | 318 | acpimcfg_init(bus_space_tag_t memt, const struct acpimcfg_ops *ops) |
319 | { | | 319 | { |
320 | ACPI_MCFG_ALLOCATION *ama; | | 320 | ACPI_MCFG_ALLOCATION *ama; |
321 | struct mcfg_segment *seg; | | 321 | struct mcfg_segment *seg; |
322 | uint32_t offset; | | 322 | uint32_t offset; |
323 | int i, n, nsegs, bus_end; | | 323 | int i, n, nsegs, bus_end; |
324 | | | 324 | |
325 | if (mcfg == NULL) | | 325 | if (mcfg == NULL) |
326 | return ENXIO; | | 326 | return ENXIO; |
327 | | | 327 | |
328 | if (mcfg_inited) | | 328 | if (mcfg_inited) |
329 | return 0; | | 329 | return 0; |
330 | | | 330 | |
331 | if (ops != NULL) | | 331 | if (ops != NULL) |
332 | mcfg_ops = ops; | | 332 | mcfg_ops = ops; |
333 | | | 333 | |
334 | nsegs = 0; | | 334 | nsegs = 0; |
335 | offset = sizeof(ACPI_TABLE_MCFG); | | 335 | offset = sizeof(ACPI_TABLE_MCFG); |
336 | ama = ACPI_ADD_PTR(ACPI_MCFG_ALLOCATION, mcfg, offset); | | 336 | ama = ACPI_ADD_PTR(ACPI_MCFG_ALLOCATION, mcfg, offset); |
337 | for (i = 0; offset < mcfg->Header.Length; i++) { | | 337 | for (i = 0; offset < mcfg->Header.Length; i++) { |
338 | #ifndef _LP64 | | 338 | #ifndef _LP64 |
339 | if (ama->Address >= 0x100000000ULL) { | | 339 | if (ama->Address >= 0x100000000ULL) { |
340 | aprint_debug_dev(acpi_sc->sc_dev, | | 340 | aprint_debug_dev(acpi_sc->sc_dev, |
341 | "MCFG: segment %d, bus %d-%d, address 0x%016" PRIx64 | | 341 | "MCFG: segment %d, bus %d-%d, address 0x%016" PRIx64 |
342 | ": ignore (64bit address)\n", ama->PciSegment, | | 342 | ": ignore (64bit address)\n", ama->PciSegment, |
343 | ama->StartBusNumber, ama->EndBusNumber, | | 343 | ama->StartBusNumber, ama->EndBusNumber, |
344 | ama->Address); | | 344 | ama->Address); |
345 | goto next; | | 345 | goto next; |
346 | } | | 346 | } |
347 | #endif | | 347 | #endif |
348 | /* | | 348 | /* |
349 | * Some (broken?) BIOSen have an MCFG table for an empty | | 349 | * Some (broken?) BIOSen have an MCFG table for an empty |
350 | * bus range. Ignore those tables. | | 350 | * bus range. Ignore those tables. |
351 | */ | | 351 | */ |
352 | if (ama->StartBusNumber > ama->EndBusNumber) { | | 352 | if (ama->StartBusNumber > ama->EndBusNumber) { |
353 | aprint_debug_dev(acpi_sc->sc_dev, | | 353 | aprint_debug_dev(acpi_sc->sc_dev, |
354 | "MCFG: segment %d, bus %d-%d, address 0x%016" PRIx64 | | 354 | "MCFG: segment %d, bus %d-%d, address 0x%016" PRIx64 |
355 | ": ignore (bus %d > %d)\n", ama->PciSegment, | | 355 | ": ignore (bus %d > %d)\n", ama->PciSegment, |
356 | ama->StartBusNumber, ama->EndBusNumber, | | 356 | ama->StartBusNumber, ama->EndBusNumber, |
357 | ama->Address, ama->StartBusNumber, | | 357 | ama->Address, ama->StartBusNumber, |
358 | ama->EndBusNumber); | | 358 | ama->EndBusNumber); |
359 | goto next; | | 359 | goto next; |
360 | } | | 360 | } |
361 | | | 361 | |
362 | /* Validate MCFG memory range */ | | 362 | /* Validate MCFG memory range */ |
363 | bus_end = ama->EndBusNumber; | | 363 | bus_end = ama->EndBusNumber; |
364 | if (mcfg_ops->ao_validate != NULL && | | 364 | if (mcfg_ops->ao_validate != NULL && |
365 | !mcfg_ops->ao_validate(ama->Address, ama->StartBusNumber, | | 365 | !mcfg_ops->ao_validate(ama->Address, ama->StartBusNumber, |
366 | &bus_end)) { | | 366 | &bus_end)) { |
367 | if (!acpimcfg_find_system_resource(ama->Address, | | 367 | if (!acpimcfg_find_system_resource(ama->Address, |
368 | ama->StartBusNumber, &bus_end)) { | | 368 | ama->StartBusNumber, &bus_end)) { |
369 | aprint_debug_dev(acpi_sc->sc_dev, | | 369 | aprint_debug_dev(acpi_sc->sc_dev, |
370 | "MCFG: segment %d, bus %d-%d, " | | 370 | "MCFG: segment %d, bus %d-%d, " |
371 | "address 0x%016" PRIx64 | | 371 | "address 0x%016" PRIx64 |
372 | ": ignore (invalid address)\n", | | 372 | ": ignore (invalid address)\n", |
373 | ama->PciSegment, | | 373 | ama->PciSegment, |
374 | ama->StartBusNumber, ama->EndBusNumber, | | 374 | ama->StartBusNumber, ama->EndBusNumber, |
375 | ama->Address); | | 375 | ama->Address); |
376 | goto next; | | 376 | goto next; |
377 | } | | 377 | } |
378 | } | | 378 | } |
379 | if (ama->EndBusNumber != bus_end) { | | 379 | if (ama->EndBusNumber != bus_end) { |
380 | aprint_debug_dev(acpi_sc->sc_dev, | | 380 | aprint_debug_dev(acpi_sc->sc_dev, |
381 | "MCFG: segment %d, bus %d-%d, address 0x%016" PRIx64 | | 381 | "MCFG: segment %d, bus %d-%d, address 0x%016" PRIx64 |
382 | " -> bus %d-%d\n", ama->PciSegment, | | 382 | " -> bus %d-%d\n", ama->PciSegment, |
383 | ama->StartBusNumber, ama->EndBusNumber, | | 383 | ama->StartBusNumber, ama->EndBusNumber, |
384 | ama->Address, ama->StartBusNumber, bus_end); | | 384 | ama->Address, ama->StartBusNumber, bus_end); |
385 | } | | 385 | } |
386 | | | 386 | |
387 | #ifndef __HAVE_PCI_GET_SEGMENT | | 387 | #ifndef __HAVE_PCI_GET_SEGMENT |
388 | if (ama->PciSegment != 0) { | | 388 | if (ama->PciSegment != 0) { |
389 | aprint_debug_dev(acpi_sc->sc_dev, | | 389 | aprint_debug_dev(acpi_sc->sc_dev, |
390 | "MCFG: segment %d, bus %d-%d, address 0x%016" PRIx64 | | 390 | "MCFG: segment %d, bus %d-%d, address 0x%016" PRIx64 |
391 | ": ignore (non PCI segment 0)\n", ama->PciSegment, | | 391 | ": ignore (non PCI segment 0)\n", ama->PciSegment, |
392 | ama->StartBusNumber, bus_end, ama->Address); | | 392 | ama->StartBusNumber, bus_end, ama->Address); |
393 | goto next; | | 393 | goto next; |
394 | } | | 394 | } |
395 | #endif | | 395 | #endif |
396 | | | 396 | |
397 | seg = &mcfg_segs[nsegs++]; | | 397 | seg = &mcfg_segs[nsegs++]; |
398 | seg->ms_address = ama->Address; | | 398 | seg->ms_address = ama->Address; |
399 | seg->ms_segment = ama->PciSegment; | | 399 | seg->ms_segment = ama->PciSegment; |
400 | seg->ms_bus_start = ama->StartBusNumber; | | 400 | seg->ms_bus_start = ama->StartBusNumber; |
401 | seg->ms_bus_end = bus_end; | | 401 | seg->ms_bus_end = bus_end; |
402 | seg->ms_bst = memt; | | 402 | seg->ms_bst = memt; |
403 | n = seg->ms_bus_end - seg->ms_bus_start + 1; | | 403 | n = seg->ms_bus_end - seg->ms_bus_start + 1; |
404 | seg->ms_bus = kmem_zalloc(sizeof(*seg->ms_bus) * n, KM_SLEEP); | | 404 | seg->ms_bus = kmem_zalloc(sizeof(*seg->ms_bus) * n, KM_SLEEP); |
405 | | | 405 | |
406 | next: | | 406 | next: |
407 | offset += sizeof(ACPI_MCFG_ALLOCATION); | | 407 | offset += sizeof(ACPI_MCFG_ALLOCATION); |
408 | ama = ACPI_ADD_PTR(ACPI_MCFG_ALLOCATION, mcfg, offset); | | 408 | ama = ACPI_ADD_PTR(ACPI_MCFG_ALLOCATION, mcfg, offset); |
409 | } | | 409 | } |
410 | if (nsegs == 0) | | 410 | if (nsegs == 0) |
411 | return ENOENT; | | 411 | return ENOENT; |
412 | | | 412 | |
413 | for (i = 0; i < nsegs; i++) { | | 413 | for (i = 0; i < nsegs; i++) { |
414 | seg = &mcfg_segs[i]; | | 414 | seg = &mcfg_segs[i]; |
415 | aprint_verbose_dev(acpi_sc->sc_dev, | | 415 | aprint_verbose_dev(acpi_sc->sc_dev, |
416 | "MCFG: segment %d, bus %d-%d, address 0x%016" PRIx64 "\n", | | 416 | "MCFG: segment %d, bus %d-%d, address 0x%016" PRIx64 "\n", |
417 | seg->ms_segment, seg->ms_bus_start, seg->ms_bus_end, | | 417 | seg->ms_segment, seg->ms_bus_start, seg->ms_bus_end, |
418 | seg->ms_address); | | 418 | seg->ms_address); |
419 | } | | 419 | } |
420 | | | 420 | |
421 | /* Update # of segment */ | | 421 | /* Update # of segment */ |
422 | mcfg_nsegs = nsegs; | | 422 | mcfg_nsegs = nsegs; |
423 | mcfg_inited = true; | | 423 | mcfg_inited = true; |
424 | | | 424 | |
425 | return 0; | | 425 | return 0; |
426 | } | | 426 | } |
427 | | | 427 | |
428 | static int | | 428 | static int |
429 | acpimcfg_ext_conf_is_aliased(pci_chipset_tag_t pc, pcitag_t tag) | | 429 | acpimcfg_ext_conf_is_aliased(pci_chipset_tag_t pc, pcitag_t tag) |
430 | { | | 430 | { |
431 | pcireg_t id; | | 431 | pcireg_t id; |
432 | int i; | | 432 | int i; |
433 | | | 433 | |
434 | id = pci_conf_read(pc, tag, PCI_ID_REG); | | 434 | id = pci_conf_read(pc, tag, PCI_ID_REG); |
435 | for (i = PCI_CONF_SIZE; i < PCI_EXTCONF_SIZE; i += PCI_CONF_SIZE) { | | 435 | for (i = PCI_CONF_SIZE; i < PCI_EXTCONF_SIZE; i += PCI_CONF_SIZE) { |
436 | if (pci_conf_read(pc, tag, i) != id) | | 436 | if (pci_conf_read(pc, tag, i) != id) |
437 | return false; | | 437 | return false; |
438 | } | | 438 | } |
439 | return true; | | 439 | return true; |
440 | } | | 440 | } |
441 | | | 441 | |
442 | static struct mcfg_segment * | | 442 | static struct mcfg_segment * |
443 | acpimcfg_get_segment(pci_chipset_tag_t pc, int bus) | | 443 | acpimcfg_get_segment(pci_chipset_tag_t pc, int bus) |
444 | { | | 444 | { |
445 | struct mcfg_segment *seg; | | 445 | struct mcfg_segment *seg; |
446 | u_int segment; | | 446 | u_int segment; |
447 | int i; | | 447 | int i; |
448 | | | 448 | |
449 | #ifdef __HAVE_PCI_GET_SEGMENT | | 449 | #ifdef __HAVE_PCI_GET_SEGMENT |
450 | segment = pci_get_segment(pc); | | 450 | segment = pci_get_segment(pc); |
451 | #else | | 451 | #else |
452 | segment = 0; | | 452 | segment = 0; |
453 | #endif | | 453 | #endif |
454 | | | 454 | |
455 | for (i = 0; i < mcfg_nsegs; i++) { | | 455 | for (i = 0; i < mcfg_nsegs; i++) { |
456 | seg = &mcfg_segs[i]; | | 456 | seg = &mcfg_segs[i]; |
457 | if (segment == seg->ms_segment && | | 457 | if (segment == seg->ms_segment && |
458 | bus >= seg->ms_bus_start && bus <= seg->ms_bus_end) | | 458 | bus >= seg->ms_bus_start && bus <= seg->ms_bus_end) |
459 | return seg; | | 459 | return seg; |
460 | } | | 460 | } |
461 | return NULL; | | 461 | return NULL; |
462 | } | | 462 | } |
463 | | | 463 | |
464 | static int | | 464 | static int |
465 | acpimcfg_device_probe(const struct pci_attach_args *pa) | | 465 | acpimcfg_device_probe(const struct pci_attach_args *pa) |
466 | { | | 466 | { |
467 | pci_chipset_tag_t pc = pa->pa_pc; | | 467 | pci_chipset_tag_t pc = pa->pa_pc; |
468 | struct mcfg_segment *seg; | | 468 | struct mcfg_segment *seg; |
469 | struct mcfg_bus *mb; | | 469 | struct mcfg_bus *mb; |
470 | pcitag_t tag; | | 470 | pcitag_t tag; |
471 | pcireg_t reg; | | 471 | pcireg_t reg; |
472 | int bus = pa->pa_bus; | | 472 | int bus = pa->pa_bus; |
473 | int dev = pa->pa_device; | | 473 | int dev = pa->pa_device; |
474 | int func = pa->pa_function; | | 474 | int func = pa->pa_function; |
475 | int last_dev, last_func, end_func; | | 475 | int last_dev, last_func, end_func; |
476 | int alias = 0; | | 476 | int alias = 0; |
477 | const struct pci_quirkdata *qd; | | 477 | const struct pci_quirkdata *qd; |
478 | bool force_hasextcnf = false; | | 478 | bool force_hasextcnf = false; |
479 | bool force_noextcnf = false; | | 479 | bool force_noextcnf = false; |
480 | int i, j; | | 480 | int i, j; |
481 | | | 481 | |
482 | seg = acpimcfg_get_segment(pc, bus); | | 482 | seg = acpimcfg_get_segment(pc, bus); |
483 | if (seg == NULL) | | 483 | if (seg == NULL) |
484 | return 0; | | 484 | return 0; |
485 | | | 485 | |
486 | mb = &seg->ms_bus[bus - seg->ms_bus_start]; | | 486 | mb = &seg->ms_bus[bus - seg->ms_bus_start]; |
487 | tag = pci_make_tag(pc, bus, dev, func); | | 487 | tag = pci_make_tag(pc, bus, dev, func); |
488 | | | 488 | |
489 | /* Mark invalid between last probed device to probed device. */ | | 489 | /* Mark invalid between last probed device to probed device. */ |
490 | pci_decompose_tag(pc, mb->last_probed, NULL, &last_dev, &last_func); | | 490 | pci_decompose_tag(pc, mb->last_probed, NULL, &last_dev, &last_func); |
491 | if (dev != 0 || func != 0) { | | 491 | if (dev != 0 || func != 0) { |
492 | for (i = last_dev; i <= dev; i++) { | | 492 | for (i = last_dev; i <= dev; i++) { |
493 | end_func = (i == dev) ? func : 8; | | 493 | end_func = (i == dev) ? func : 8; |
494 | for (j = last_func; j < end_func; j++) { | | 494 | for (j = last_func; j < end_func; j++) { |
495 | if (i == last_dev && j == last_func) | | 495 | if (i == last_dev && j == last_func) |
496 | continue; | | 496 | continue; |
497 | PCIDEV_SET_INVALID(mb, i, j); | | 497 | PCIDEV_SET_INVALID(mb, i, j); |
498 | } | | 498 | } |
499 | last_func = 0; | | 499 | last_func = 0; |
500 | } | | 500 | } |
501 | } | | 501 | } |
502 | mb->last_probed = tag; | | 502 | mb->last_probed = tag; |
503 | | | 503 | |
504 | reg = pci_conf_read(pc, tag, PCI_ID_REG); | | 504 | reg = pci_conf_read(pc, tag, PCI_ID_REG); |
505 | qd = pci_lookup_quirkdata(PCI_VENDOR(reg), PCI_PRODUCT(reg)); | | 505 | qd = pci_lookup_quirkdata(PCI_VENDOR(reg), PCI_PRODUCT(reg)); |
506 | if (qd != NULL && (qd->quirks & PCI_QUIRK_HASEXTCNF) != 0) | | 506 | if (qd != NULL && (qd->quirks & PCI_QUIRK_HASEXTCNF) != 0) |
507 | force_hasextcnf = true; | | 507 | force_hasextcnf = true; |
508 | if (qd != NULL && (qd->quirks & PCI_QUIRK_NOEXTCNF) != 0) | | 508 | if (qd != NULL && (qd->quirks & PCI_QUIRK_NOEXTCNF) != 0) |
509 | force_noextcnf = true; | | 509 | force_noextcnf = true; |
510 | | | 510 | |
511 | /* Probe extended configuration space. */ | | 511 | /* Probe extended configuration space. */ |
512 | if ((!force_hasextcnf) && ((force_noextcnf) || | | 512 | if ((!force_hasextcnf) && ((force_noextcnf) || |
513 | ((reg = pci_conf_read(pc, tag, PCI_CONF_SIZE)) == (pcireg_t)-1) | | 513 | ((reg = pci_conf_read(pc, tag, PCI_CONF_SIZE)) == (pcireg_t)-1) |
514 | || (reg == 0) | | 514 | || (reg == 0) |
515 | || (alias = acpimcfg_ext_conf_is_aliased(pc, tag)))) { | | 515 | || (alias = acpimcfg_ext_conf_is_aliased(pc, tag)))) { |
516 | aprint_debug_dev(acpi_sc->sc_dev, | | 516 | aprint_debug_dev(acpi_sc->sc_dev, |
517 | "MCFG: %03d:%02d:%d: invalid config space " | | 517 | "MCFG: %03d:%02d:%d: invalid config space " |
518 | "(cfg[0x%03x]=0x%08x, alias=%s)\n", bus, dev, func, | | 518 | "(cfg[0x%03x]=0x%08x, alias=%s)\n", bus, dev, func, |
519 | PCI_CONF_SIZE, reg, alias ? "true" : "false"); | | 519 | PCI_CONF_SIZE, reg, alias ? "true" : "false"); |
520 | EXTCONF_SET_INVALID(mb, dev, func); | | 520 | EXTCONF_SET_INVALID(mb, dev, func); |
521 | } | | 521 | } |
522 | | | 522 | |
523 | aprint_debug_dev(acpi_sc->sc_dev, | | 523 | aprint_debug_dev(acpi_sc->sc_dev, |
524 | "MCFG: %03d:%02d:%d: Ok (cfg[0x%03x]=0x%08x extconf=%c)\n", | | 524 | "MCFG: %03d:%02d:%d: Ok (cfg[0x%03x]=0x%08x extconf=%c)\n", |
525 | bus, dev, func, PCI_CONF_SIZE, reg, | | 525 | bus, dev, func, PCI_CONF_SIZE, reg, |
526 | EXTCONF_IS_VALID(mb, dev, func) ? 'Y' : 'N'); | | 526 | EXTCONF_IS_VALID(mb, dev, func) ? 'Y' : 'N'); |
527 | mb->valid_ndevs++; | | 527 | mb->valid_ndevs++; |
528 | | | 528 | |
529 | return 0; | | 529 | return 0; |
530 | } | | 530 | } |
531 | | | 531 | |
532 | #ifdef PCI_MACHDEP_ENUMERATE_BUS | | 532 | #ifdef PCI_MACHDEP_ENUMERATE_BUS |
533 | #define pci_enumerate_bus PCI_MACHDEP_ENUMERATE_BUS | | 533 | #define pci_enumerate_bus PCI_MACHDEP_ENUMERATE_BUS |
534 | #endif | | 534 | #endif |
535 | | | 535 | |
536 | static void | | 536 | static void |
537 | acpimcfg_scan_bus(struct pci_softc *sc, pci_chipset_tag_t pc, int bus) | | 537 | acpimcfg_scan_bus(struct pci_softc *sc, pci_chipset_tag_t pc, int bus) |
538 | { | | 538 | { |
539 | static const int wildcard[PCICF_NLOCS] = { | | 539 | static const int wildcard[PCICF_NLOCS] = { |
540 | PCICF_DEV_DEFAULT, PCICF_FUNCTION_DEFAULT | | 540 | PCICF_DEV_DEFAULT, PCICF_FUNCTION_DEFAULT |
541 | }; | | 541 | }; |
542 | | | 542 | |
543 | sc->sc_bus = bus; /* XXX */ | | 543 | sc->sc_bus = bus; /* XXX */ |
544 | sc->sc_pc = pc; | | 544 | sc->sc_pc = pc; |
545 | | | 545 | |
546 | pci_enumerate_bus(sc, wildcard, acpimcfg_device_probe, NULL); | | 546 | pci_enumerate_bus(sc, wildcard, acpimcfg_device_probe, NULL); |
547 | } | | 547 | } |
548 | | | 548 | |
549 | int | | 549 | int |
550 | acpimcfg_map_bus(device_t self, pci_chipset_tag_t pc, int bus) | | 550 | acpimcfg_map_bus(device_t self, pci_chipset_tag_t pc, int bus) |
551 | { | | 551 | { |
552 | struct pci_softc *sc = device_private(self); | | 552 | struct pci_softc *sc = device_private(self); |
553 | struct mcfg_segment *seg = NULL; | | 553 | struct mcfg_segment *seg = NULL; |
554 | struct mcfg_bus *mb; | | 554 | struct mcfg_bus *mb; |
555 | bus_space_handle_t bsh; | | 555 | bus_space_handle_t bsh; |
556 | bus_addr_t baddr; | | 556 | bus_addr_t baddr; |
557 | pcitag_t tag; | | 557 | pcitag_t tag; |
558 | pcireg_t reg; | | 558 | pcireg_t reg; |
559 | bool is_e7520_mch; | | 559 | bool is_e7520_mch; |
560 | int boff; | | 560 | int boff; |
561 | int last_dev, last_func; | | 561 | int last_dev, last_func; |
562 | int i, j; | | 562 | int i, j; |
563 | int error; | | 563 | int error; |
564 | | | 564 | |
565 | if (!mcfg_inited) | | 565 | if (!mcfg_inited) |
566 | return ENXIO; | | 566 | return ENXIO; |
567 | | | 567 | |
568 | seg = acpimcfg_get_segment(pc, bus); | | 568 | seg = acpimcfg_get_segment(pc, bus); |
569 | if (seg == NULL) | | 569 | if (seg == NULL) |
570 | return ENOENT; | | 570 | return ENOENT; |
571 | | | 571 | |
572 | boff = bus - seg->ms_bus_start; | | 572 | boff = bus - seg->ms_bus_start; |
573 | if (seg->ms_bus[boff].valid_ndevs > 0) | | 573 | if (seg->ms_bus[boff].valid_ndevs > 0) |
574 | return 0; | | 574 | return 0; |
575 | | | 575 | |
576 | mb = &seg->ms_bus[boff]; | | 576 | mb = &seg->ms_bus[boff]; |
577 | baddr = seg->ms_address + (bus * ACPIMCFG_SIZE_PER_BUS); | | 577 | baddr = seg->ms_address + (bus * ACPIMCFG_SIZE_PER_BUS); |
578 | | | 578 | |
579 | /* Map extended configuration space of all dev/func. */ | | 579 | /* Map extended configuration space of all dev/func. */ |
580 | error = bus_space_map(seg->ms_bst, baddr, ACPIMCFG_SIZE_PER_BUS, 0, | | 580 | error = bus_space_map(seg->ms_bst, baddr, ACPIMCFG_SIZE_PER_BUS, 0, |
581 | &bsh); | | 581 | &bsh); |
582 | if (error != 0) | | 582 | if (error != 0) |
583 | return error; | | 583 | return error; |
584 | for (i = 0; i < 32; i++) { | | 584 | for (i = 0; i < 32; i++) { |
585 | for (j = 0; j < 8; j++) { | | 585 | for (j = 0; j < 8; j++) { |
586 | error = bus_space_subregion(seg->ms_bst, bsh, | | 586 | error = bus_space_subregion(seg->ms_bst, bsh, |
587 | EXTCONF_OFFSET(i, j, 0), PCI_EXTCONF_SIZE, | | 587 | EXTCONF_OFFSET(i, j, 0), PCI_EXTCONF_SIZE, |
588 | &mb->bsh[i][j]); | | 588 | &mb->bsh[i][j]); |
589 | if (error != 0) | | 589 | if (error != 0) |
590 | break; | | 590 | break; |
591 | } | | 591 | } |
592 | } | | 592 | } |
593 | if (error != 0) | | 593 | if (error != 0) |
594 | return error; | | 594 | return error; |
595 | | | 595 | |
596 | aprint_debug("\n"); | | 596 | aprint_debug("\n"); |
597 | | | 597 | |
598 | /* Probe extended configuration space of all devices. */ | | 598 | /* Probe extended configuration space of all devices. */ |
599 | memset(mb->valid_devs, 0xff, sizeof(mb->valid_devs)); | | 599 | memset(mb->valid_devs, 0xff, sizeof(mb->valid_devs)); |
600 | memset(mb->valid_extconf, 0xff, sizeof(mb->valid_extconf)); | | 600 | memset(mb->valid_extconf, 0xff, sizeof(mb->valid_extconf)); |
601 | mb->valid_ndevs = 0; | | 601 | mb->valid_ndevs = 0; |
602 | mb->last_probed = pci_make_tag(pc, bus, 0, 0); | | 602 | mb->last_probed = pci_make_tag(pc, bus, 0, 0); |
603 | | | 603 | |
604 | /* | | 604 | /* |
605 | * On an Intel E7520 we have to temporarily disable | | 605 | * On an Intel E7520 we have to temporarily disable |
606 | * Enhanced Config Access error detection and reporting | | 606 | * Enhanced Config Access error detection and reporting |
607 | * by setting the appropriate error mask in HI_ERRMASK register. | | 607 | * by setting the appropriate error mask in HI_ERRMASK register. |
608 | * | | 608 | * |
609 | * See "Intel E7520 Memory Controller Hub (MCH) Datasheet", | | 609 | * See "Intel E7520 Memory Controller Hub (MCH) Datasheet", |
610 | * Document 303006-002, pg. 82 | | 610 | * Document 303006-002, pg. 82 |
611 | */ | | 611 | */ |
612 | tag = pci_make_tag(pc, 0, 0, 1); | | 612 | tag = pci_make_tag(pc, 0, 0, 1); |
613 | reg = pci_conf_read(pc, tag, PCI_ID_REG); | | 613 | reg = pci_conf_read(pc, tag, PCI_ID_REG); |
614 | is_e7520_mch = (reg == | | 614 | is_e7520_mch = (reg == |
615 | PCI_ID_CODE(PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_E7525_MCHER)); | | 615 | PCI_ID_CODE(PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_E7525_MCHER)); |
616 | if (is_e7520_mch) { | | 616 | if (is_e7520_mch) { |
617 | reg = pci_conf_read(pc, tag, 0x54); | | 617 | reg = pci_conf_read(pc, tag, 0x54); |
618 | pci_conf_write(pc, tag, 0x54, reg | 0x20); | | 618 | pci_conf_write(pc, tag, 0x54, reg | 0x20); |
619 | } | | 619 | } |
620 | | | 620 | |
621 | acpimcfg_scan_bus(sc, pc, bus); | | 621 | acpimcfg_scan_bus(sc, pc, bus); |
622 | | | 622 | |
623 | if (is_e7520_mch) { | | 623 | if (is_e7520_mch) { |
624 | pci_conf_write(pc, tag, 0x54, reg); | | 624 | pci_conf_write(pc, tag, 0x54, reg); |
625 | } | | 625 | } |
626 | | | 626 | |
627 | /* Unmap configuration space of all dev/func. */ | | 627 | /* Unmap configuration space of all dev/func. */ |
628 | bus_space_unmap(seg->ms_bst, bsh, ACPIMCFG_SIZE_PER_BUS); | | 628 | bus_space_unmap(seg->ms_bst, bsh, ACPIMCFG_SIZE_PER_BUS); |
629 | memset(mb->bsh, 0, sizeof(mb->bsh)); | | 629 | memset(mb->bsh, 0, sizeof(mb->bsh)); |
630 | | | 630 | |
631 | if (mb->valid_ndevs == 0) { | | 631 | if (mb->valid_ndevs == 0) { |
632 | aprint_debug_dev(acpi_sc->sc_dev, | | 632 | aprint_debug_dev(acpi_sc->sc_dev, |
633 | "MCFG: bus %d: no valid devices.\n", bus); | | 633 | "MCFG: bus %d: no valid devices.\n", bus); |
634 | memset(mb->valid_devs, 0, sizeof(mb->valid_devs)); | | 634 | memset(mb->valid_devs, 0, sizeof(mb->valid_devs)); |
635 | goto out; | | 635 | goto out; |
636 | } | | 636 | } |
637 | | | 637 | |
638 | /* Mark invalid on remaining all devices. */ | | 638 | /* Mark invalid on remaining all devices. */ |
639 | pci_decompose_tag(pc, mb->last_probed, NULL, &last_dev, &last_func); | | 639 | pci_decompose_tag(pc, mb->last_probed, NULL, &last_dev, &last_func); |
640 | for (i = last_dev; i < 32; i++) { | | 640 | for (i = last_dev; i < 32; i++) { |
641 | for (j = last_func; j < 8; j++) { | | 641 | for (j = last_func; j < 8; j++) { |
642 | if (i == last_dev && j == last_func) { | | 642 | if (i == last_dev && j == last_func) { |
643 | /* Don't mark invalid to last probed device. */ | | 643 | /* Don't mark invalid to last probed device. */ |
644 | continue; | | 644 | continue; |
645 | } | | 645 | } |
646 | PCIDEV_SET_INVALID(mb, i, j); | | 646 | PCIDEV_SET_INVALID(mb, i, j); |
647 | } | | 647 | } |
648 | last_func = 0; | | 648 | last_func = 0; |
649 | } | | 649 | } |
650 | | | 650 | |
651 | /* Map configuration space per dev/func. */ | | 651 | /* Map configuration space per dev/func. */ |
652 | for (i = 0; i < 32; i++) { | | 652 | for (i = 0; i < 32; i++) { |
653 | for (j = 0; j < 8; j++) { | | 653 | for (j = 0; j < 8; j++) { |
654 | if (!PCIDEV_IS_VALID(mb, i, j)) | | 654 | if (!PCIDEV_IS_VALID(mb, i, j)) |
655 | continue; | | 655 | continue; |
656 | error = bus_space_map(seg->ms_bst, | | 656 | error = bus_space_map(seg->ms_bst, |
657 | baddr + EXTCONF_OFFSET(i, j, 0), PCI_EXTCONF_SIZE, | | 657 | baddr + EXTCONF_OFFSET(i, j, 0), PCI_EXTCONF_SIZE, |
658 | 0, &mb->bsh[i][j]); | | 658 | 0, &mb->bsh[i][j]); |
659 | if (error != 0) { | | 659 | if (error != 0) { |
660 | /* Unmap all handles when map failed. */ | | 660 | /* Unmap all handles when map failed. */ |
661 | do { | | 661 | do { |
662 | while (--j >= 0) { | | 662 | while (--j >= 0) { |
663 | if (!PCIDEV_IS_VALID(mb, i, j)) | | 663 | if (!PCIDEV_IS_VALID(mb, i, j)) |
664 | continue; | | 664 | continue; |
665 | bus_space_unmap(seg->ms_bst, | | 665 | bus_space_unmap(seg->ms_bst, |
666 | mb->bsh[i][j], | | 666 | mb->bsh[i][j], |
667 | PCI_EXTCONF_SIZE); | | 667 | PCI_EXTCONF_SIZE); |
668 | } | | 668 | } |
669 | j = 8; | | 669 | j = 8; |
670 | } while (--i >= 0); | | 670 | } while (--i >= 0); |
671 | memset(mb->valid_devs, 0, | | 671 | memset(mb->valid_devs, 0, |
672 | sizeof(mb->valid_devs)); | | 672 | sizeof(mb->valid_devs)); |
673 | goto out; | | 673 | goto out; |
674 | } | | 674 | } |
675 | } | | 675 | } |
676 | } | | 676 | } |
677 | | | 677 | |
678 | aprint_debug_dev(acpi_sc->sc_dev, "MCFG: bus %d: valid devices\n", bus); | | 678 | aprint_debug_dev(acpi_sc->sc_dev, "MCFG: bus %d: valid devices\n", bus); |
679 | for (i = 0; i < 32; i++) { | | 679 | for (i = 0; i < 32; i++) { |
680 | for (j = 0; j < 8; j++) { | | 680 | for (j = 0; j < 8; j++) { |
681 | if (PCIDEV_IS_VALID(mb, i, j)) { | | 681 | if (PCIDEV_IS_VALID(mb, i, j)) { |
682 | aprint_debug_dev(acpi_sc->sc_dev, | | 682 | aprint_debug_dev(acpi_sc->sc_dev, |
683 | "MCFG: %03d:%02d:%d\n", bus, i, j); | | 683 | "MCFG: %03d:%02d:%d\n", bus, i, j); |
684 | } | | 684 | } |
685 | } | | 685 | } |
686 | } | | 686 | } |
687 | | | 687 | |
688 | error = 0; | | 688 | error = 0; |
689 | out: | | 689 | out: |
690 | aprint_debug_dev(acpi_sc->sc_dev, "%s done", __func__); | | 690 | aprint_debug_dev(acpi_sc->sc_dev, "%s done", __func__); |
691 | | | 691 | |
692 | return error; | | 692 | return error; |
693 | } | | 693 | } |
694 | | | 694 | |
695 | #ifdef PCI_NETBSD_CONFIGURE | | 695 | #ifdef PCI_NETBSD_CONFIGURE |
696 | static ACPI_STATUS | | 696 | static ACPI_STATUS |
697 | acpimcfg_configure_bus_cb(ACPI_RESOURCE *res, void *ctx) | | 697 | acpimcfg_configure_bus_cb(ACPI_RESOURCE *res, void *ctx) |
698 | { | | 698 | { |
699 | struct pciconf_resources *pcires = ctx; | | 699 | struct pciconf_resources *pcires = ctx; |
700 | int type; | | 700 | int type; |
701 | bus_addr_t addr; | | 701 | bus_addr_t addr; |
702 | bus_size_t size; | | 702 | bus_size_t size; |
703 | const char *s; | | 703 | const char *s; |
704 | int error; | | 704 | int error; |
705 | | | 705 | |
706 | if (res->Type != ACPI_RESOURCE_TYPE_ADDRESS16 && | | 706 | if (res->Type != ACPI_RESOURCE_TYPE_ADDRESS16 && |
707 | res->Type != ACPI_RESOURCE_TYPE_ADDRESS32 && | | 707 | res->Type != ACPI_RESOURCE_TYPE_ADDRESS32 && |
708 | res->Type != ACPI_RESOURCE_TYPE_ADDRESS64) | | 708 | res->Type != ACPI_RESOURCE_TYPE_ADDRESS64) |
709 | return AE_OK; | | 709 | return AE_OK; |
710 | | | 710 | |
711 | if (res->Data.Address.ProducerConsumer != ACPI_PRODUCER) | | 711 | if (res->Data.Address.ProducerConsumer != ACPI_PRODUCER) |
712 | return AE_OK; | | 712 | return AE_OK; |
713 | | | 713 | |
714 | if (res->Data.Address.ResourceType != ACPI_MEMORY_RANGE && | | 714 | if (res->Data.Address.ResourceType != ACPI_MEMORY_RANGE && |
715 | res->Data.Address.ResourceType != ACPI_IO_RANGE) | | 715 | res->Data.Address.ResourceType != ACPI_IO_RANGE) |
716 | return AE_OK; | | 716 | return AE_OK; |
717 | | | 717 | |
718 | if (res->Data.Address.ResourceType == ACPI_MEMORY_RANGE && | | 718 | if (res->Data.Address.ResourceType == ACPI_MEMORY_RANGE && |
719 | res->Data.Address.Info.Mem.Caching == ACPI_PREFETCHABLE_MEMORY) { | | 719 | res->Data.Address.Info.Mem.Caching == ACPI_PREFETCHABLE_MEMORY) { |
720 | type = PCICONF_RESOURCE_PREFETCHABLE_MEM; | | 720 | type = PCICONF_RESOURCE_PREFETCHABLE_MEM; |
721 | s = "prefetchable"; | | 721 | s = "prefetchable"; |
722 | } else if (res->Data.Address.ResourceType == ACPI_MEMORY_RANGE && | | 722 | } else if (res->Data.Address.ResourceType == ACPI_MEMORY_RANGE && |
723 | res->Data.Address.Info.Mem.Caching != ACPI_PREFETCHABLE_MEMORY) { | | 723 | res->Data.Address.Info.Mem.Caching != ACPI_PREFETCHABLE_MEMORY) { |
724 | type = PCICONF_RESOURCE_MEM; | | 724 | type = PCICONF_RESOURCE_MEM; |
725 | s = "non-prefetchable"; | | 725 | s = "non-prefetchable"; |
726 | } else { | | 726 | } else { |
727 | KASSERT(res->Data.Address.ResourceType == ACPI_IO_RANGE); | | 727 | KASSERT(res->Data.Address.ResourceType == ACPI_IO_RANGE); |
728 | type = PCICONF_RESOURCE_IO; | | 728 | type = PCICONF_RESOURCE_IO; |
729 | s = "i/o"; | | 729 | s = "i/o"; |
730 | } | | 730 | } |
731 | | | 731 | |
732 | switch (res->Type) { | | 732 | switch (res->Type) { |
733 | case ACPI_RESOURCE_TYPE_ADDRESS16: | | 733 | case ACPI_RESOURCE_TYPE_ADDRESS16: |
734 | aprint_debug( | | 734 | aprint_debug( |
735 | "MCFG: range 0x%04" PRIx16 " size %#" PRIx16 " (16-bit %s)\n", | | 735 | "MCFG: range 0x%04" PRIx16 " size %#" PRIx16 " (16-bit %s)\n", |
736 | res->Data.Address16.Address.Minimum, | | 736 | res->Data.Address16.Address.Minimum, |
737 | res->Data.Address16.Address.AddressLength, | | 737 | res->Data.Address16.Address.AddressLength, |
738 | s); | | 738 | s); |
739 | addr = res->Data.Address16.Address.Minimum; | | 739 | addr = res->Data.Address16.Address.Minimum; |
740 | size = res->Data.Address16.Address.AddressLength; | | 740 | size = res->Data.Address16.Address.AddressLength; |
741 | break; | | 741 | break; |
742 | case ACPI_RESOURCE_TYPE_ADDRESS32: | | 742 | case ACPI_RESOURCE_TYPE_ADDRESS32: |
743 | aprint_debug( | | 743 | aprint_debug( |
744 | "MCFG: range 0x%08" PRIx32 " size %#" PRIx32 " (32-bit %s)\n", | | 744 | "MCFG: range 0x%08" PRIx32 " size %#" PRIx32 " (32-bit %s)\n", |
745 | res->Data.Address32.Address.Minimum, | | 745 | res->Data.Address32.Address.Minimum, |
746 | res->Data.Address32.Address.AddressLength, | | 746 | res->Data.Address32.Address.AddressLength, |
747 | s); | | 747 | s); |
748 | addr = res->Data.Address32.Address.Minimum; | | 748 | addr = res->Data.Address32.Address.Minimum; |
749 | size = res->Data.Address32.Address.AddressLength; | | 749 | size = res->Data.Address32.Address.AddressLength; |
750 | break; | | 750 | break; |
751 | case ACPI_RESOURCE_TYPE_ADDRESS64: | | 751 | case ACPI_RESOURCE_TYPE_ADDRESS64: |
752 | aprint_debug( | | 752 | aprint_debug( |
753 | "MCFG: range 0x%016" PRIx64 " size %#" PRIx64 " (64-bit %s)\n", | | 753 | "MCFG: range 0x%016" PRIx64 " size %#" PRIx64 " (64-bit %s)\n", |
754 | res->Data.Address64.Address.Minimum, | | 754 | res->Data.Address64.Address.Minimum, |
755 | res->Data.Address64.Address.AddressLength, | | 755 | res->Data.Address64.Address.AddressLength, |
756 | s); | | 756 | s); |
757 | addr = res->Data.Address64.Address.Minimum; | | 757 | addr = res->Data.Address64.Address.Minimum; |
758 | size = res->Data.Address64.Address.AddressLength; | | 758 | size = res->Data.Address64.Address.AddressLength; |
759 | break; | | 759 | break; |
760 | | | 760 | |
761 | default: | | 761 | default: |
762 | return AE_OK; | | 762 | return AE_OK; |
763 | } | | 763 | } |
764 | | | 764 | |
765 | error = pciconf_resource_add(pcires, type, addr, size); | | 765 | error = pciconf_resource_add(pcires, type, addr, size); |
766 | | | 766 | |
767 | return error == 0 ? AE_OK : AE_NO_MEMORY; | | 767 | return error == 0 ? AE_OK : AE_NO_MEMORY; |
768 | } | | 768 | } |
769 | | | 769 | |
770 | int | | 770 | int |
771 | acpimcfg_configure_bus(device_t self, pci_chipset_tag_t pc, ACPI_HANDLE handle, | | 771 | acpimcfg_configure_bus(device_t self, pci_chipset_tag_t pc, ACPI_HANDLE handle, |
772 | int bus, int cacheline_size) | | 772 | int bus, int cacheline_size) |
773 | { | | 773 | { |
774 | struct pciconf_resources *pcires; | | 774 | struct pciconf_resources *pcires; |
775 | struct mcfg_segment *seg; | | 775 | struct mcfg_segment *seg; |
776 | struct mcfg_bus *mb; | | 776 | struct mcfg_bus *mb; |
777 | bus_space_handle_t bsh[256]; | | 777 | bus_space_handle_t bsh[256]; |
778 | bool bsh_mapped[256]; | | 778 | bool bsh_mapped[256]; |
779 | int error, boff, b, d, f; | | 779 | int error, boff, b, d, f; |
780 | bus_addr_t baddr; | | 780 | bus_addr_t baddr; |
781 | ACPI_STATUS rv; | | 781 | ACPI_STATUS rv; |
782 | | | 782 | |
783 | seg = acpimcfg_get_segment(pc, bus); | | 783 | seg = acpimcfg_get_segment(pc, bus); |
784 | if (seg == NULL) | | 784 | if (seg == NULL) |
785 | return ENOENT; | | 785 | return ENOENT; |
786 | | | 786 | |
787 | pcires = pciconf_resource_init(); | | 787 | pcires = pciconf_resource_init(); |
788 | | | 788 | |
789 | /* | | 789 | /* |
790 | * Map config space for all possible busses and mark them valid during | | 790 | * Map config space for all possible busses and mark them valid during |
791 | * configuration so pci_configure_bus can access them through our chipset | | 791 | * configuration so pci_configure_bus can access them through our chipset |
792 | * tag with acpimcfg_conf_read/write below. | | 792 | * tag with acpimcfg_conf_read/write below. |
793 | */ | | 793 | */ |
794 | memset(bsh_mapped, 0, sizeof(bsh_mapped)); | | 794 | memset(bsh_mapped, 0, sizeof(bsh_mapped)); |
795 | for (b = seg->ms_bus_start; b <= seg->ms_bus_end; b++) { | | 795 | for (b = seg->ms_bus_start; b <= seg->ms_bus_end; b++) { |
796 | boff = b - seg->ms_bus_start; | | 796 | boff = b - seg->ms_bus_start; |
797 | mb = &seg->ms_bus[boff]; | | 797 | mb = &seg->ms_bus[boff]; |
798 | baddr = seg->ms_address + (b * ACPIMCFG_SIZE_PER_BUS); | | 798 | baddr = seg->ms_address + (b * ACPIMCFG_SIZE_PER_BUS); |
799 | | | 799 | |
800 | /* Map extended configuration space of all dev/func. */ | | 800 | /* Map extended configuration space of all dev/func. */ |
801 | error = bus_space_map(seg->ms_bst, baddr, ACPIMCFG_SIZE_PER_BUS, 0, | | 801 | error = bus_space_map(seg->ms_bst, baddr, ACPIMCFG_SIZE_PER_BUS, 0, |
802 | &bsh[b]); | | 802 | &bsh[b]); |
803 | if (error != 0) | | 803 | if (error != 0) |
804 | goto cleanup; | | 804 | goto cleanup; |
805 | bsh_mapped[b] = true; | | 805 | bsh_mapped[b] = true; |
806 | for (d = 0; d < 32; d++) { | | 806 | for (d = 0; d < 32; d++) { |
807 | for (f = 0; f < 8; f++) { | | 807 | for (f = 0; f < 8; f++) { |
808 | error = bus_space_subregion(seg->ms_bst, bsh[b], | | 808 | error = bus_space_subregion(seg->ms_bst, bsh[b], |
809 | EXTCONF_OFFSET(d, f, 0), PCI_EXTCONF_SIZE, | | 809 | EXTCONF_OFFSET(d, f, 0), PCI_EXTCONF_SIZE, |
810 | &mb->bsh[d][f]); | | 810 | &mb->bsh[d][f]); |
811 | if (error != 0) | | 811 | if (error != 0) |
812 | break; | | 812 | break; |
813 | } | | 813 | } |
814 | } | | 814 | } |
815 | if (error != 0) | | 815 | if (error != 0) |
816 | goto cleanup; | | 816 | goto cleanup; |
817 | | | 817 | |
818 | memset(mb->valid_devs, 0xff, sizeof(mb->valid_devs)); | | 818 | memset(mb->valid_devs, 0xff, sizeof(mb->valid_devs)); |
819 | } | | 819 | } |
820 | | | 820 | |
821 | rv = AcpiWalkResources(handle, "_CRS", acpimcfg_configure_bus_cb, | | 821 | rv = AcpiWalkResources(handle, "_CRS", acpimcfg_configure_bus_cb, |
822 | pcires); | | 822 | pcires); |
823 | if (ACPI_FAILURE(rv)) { | | 823 | if (ACPI_FAILURE(rv)) { |
824 | error = ENXIO; | | 824 | error = ENXIO; |
825 | goto cleanup; | | 825 | goto cleanup; |
826 | } | | 826 | } |
827 | | | 827 | |
828 | error = pci_configure_bus(pc, pcires, bus, cacheline_size); | | 828 | error = pci_configure_bus(pc, pcires, bus, cacheline_size); |
829 | | | 829 | |
830 | cleanup: | | 830 | cleanup: |
831 | /* | | 831 | /* |
832 | * Unmap config space for the segment's busses. Valid devices will be | | 832 | * Unmap config space for the segment's busses. Valid devices will be |
833 | * re-mapped later on by acpimcfg_map_bus. | | 833 | * re-mapped later on by acpimcfg_map_bus. |
834 | */ | | 834 | */ |
835 | for (b = seg->ms_bus_start; b <= seg->ms_bus_end; b++) { | | 835 | for (b = seg->ms_bus_start; b <= seg->ms_bus_end; b++) { |
836 | boff = b - seg->ms_bus_start; | | 836 | boff = b - seg->ms_bus_start; |
837 | mb = &seg->ms_bus[boff]; | | 837 | mb = &seg->ms_bus[boff]; |
838 | memset(mb->valid_devs, 0, sizeof(mb->valid_devs)); | | 838 | memset(mb->valid_devs, 0, sizeof(mb->valid_devs)); |
839 | | | 839 | |
840 | if (bsh_mapped[b]) | | 840 | if (bsh_mapped[b]) |
841 | bus_space_unmap(seg->ms_bst, bsh[b], ACPIMCFG_SIZE_PER_BUS); | | 841 | bus_space_unmap(seg->ms_bst, bsh[b], ACPIMCFG_SIZE_PER_BUS); |
842 | } | | 842 | } |
843 | | | 843 | |
844 | pciconf_resource_fini(pcires); | | 844 | pciconf_resource_fini(pcires); |
845 | | | 845 | |
846 | return error; | | 846 | return error; |
847 | } | | 847 | } |
848 | #else | | 848 | #else |
849 | int | | 849 | int |
850 | acpimcfg_configure_bus(device_t self, pci_chipset_tag_t pc, ACPI_HANDLE handle, | | 850 | acpimcfg_configure_bus(device_t self, pci_chipset_tag_t pc, ACPI_HANDLE handle, |
851 | int bus, int cacheline_size) | | 851 | int bus, int cacheline_size) |
852 | { | | 852 | { |
853 | return ENXIO; | | 853 | return ENXIO; |
854 | } | | 854 | } |
855 | #endif | | 855 | #endif |
856 | | | 856 | |
857 | int | | 857 | int |
858 | acpimcfg_conf_read(pci_chipset_tag_t pc, pcitag_t tag, int reg, pcireg_t *data) | | 858 | acpimcfg_conf_read(pci_chipset_tag_t pc, pcitag_t tag, int reg, pcireg_t *data) |
859 | { | | 859 | { |
860 | struct mcfg_segment *seg = NULL; | | 860 | struct mcfg_segment *seg = NULL; |
861 | struct mcfg_bus *mb; | | 861 | struct mcfg_bus *mb; |
862 | int bus, dev, func; | | 862 | int bus, dev, func; |
863 | | | 863 | |
864 | KASSERT(reg < PCI_EXTCONF_SIZE); | | 864 | KASSERT(reg < PCI_EXTCONF_SIZE); |
865 | KASSERT((reg & 3) == 0); | | 865 | KASSERT((reg & 3) == 0); |
866 | | | 866 | |
867 | if (!mcfg_inited) { | | 867 | if (!mcfg_inited) { |
868 | *data = -1; | | 868 | *data = -1; |
869 | return ENXIO; | | 869 | return ENXIO; |
870 | } | | 870 | } |
871 | | | 871 | |
872 | pci_decompose_tag(pc, tag, &bus, &dev, &func); | | 872 | pci_decompose_tag(pc, tag, &bus, &dev, &func); |
873 | | | 873 | |
874 | seg = acpimcfg_get_segment(pc, bus); | | 874 | seg = acpimcfg_get_segment(pc, bus); |
875 | if (seg == NULL) { | | 875 | if (seg == NULL) { |
876 | *data = -1; | | 876 | *data = -1; |
877 | return ERANGE; | | 877 | return ERANGE; |
878 | } | | 878 | } |
879 | | | 879 | |
880 | mb = &seg->ms_bus[bus - seg->ms_bus_start]; | | 880 | mb = &seg->ms_bus[bus - seg->ms_bus_start]; |
881 | if (!PCIDEV_IS_VALID(mb, dev, func)) { | | 881 | if (!PCIDEV_IS_VALID(mb, dev, func)) { |
882 | *data = -1; | | 882 | *data = -1; |
883 | return EINVAL; | | 883 | return EINVAL; |
884 | } | | 884 | } |
885 | if (!EXTCONF_IS_VALID(mb, dev, func) && reg >= PCI_CONF_SIZE) { | | 885 | if (!EXTCONF_IS_VALID(mb, dev, func) && reg >= PCI_CONF_SIZE) { |
886 | *data = -1; | | 886 | *data = -1; |
887 | return EINVAL; | | 887 | return EINVAL; |
888 | } | | 888 | } |
889 | | | 889 | |
890 | *data = mcfg_ops->ao_read(seg->ms_bst, mb->bsh[dev][func], reg); | | 890 | *data = mcfg_ops->ao_read(seg->ms_bst, mb->bsh[dev][func], reg); |
891 | return 0; | | 891 | return 0; |
892 | } | | 892 | } |
893 | | | 893 | |
894 | int | | 894 | int |
895 | acpimcfg_conf_write(pci_chipset_tag_t pc, pcitag_t tag, int reg, pcireg_t data) | | 895 | acpimcfg_conf_write(pci_chipset_tag_t pc, pcitag_t tag, int reg, pcireg_t data) |
896 | { | | 896 | { |
897 | struct mcfg_segment *seg = NULL; | | 897 | struct mcfg_segment *seg = NULL; |
898 | struct mcfg_bus *mb; | | 898 | struct mcfg_bus *mb; |
899 | int bus, dev, func; | | 899 | int bus, dev, func; |
900 | | | 900 | |
901 | KASSERT(reg < PCI_EXTCONF_SIZE); | | 901 | KASSERT(reg < PCI_EXTCONF_SIZE); |
902 | KASSERT((reg & 3) == 0); | | 902 | KASSERT((reg & 3) == 0); |
903 | | | 903 | |
904 | if (!mcfg_inited) | | 904 | if (!mcfg_inited) |
905 | return ENXIO; | | 905 | return ENXIO; |
906 | | | 906 | |
907 | pci_decompose_tag(pc, tag, &bus, &dev, &func); | | 907 | pci_decompose_tag(pc, tag, &bus, &dev, &func); |
908 | | | 908 | |
909 | seg = acpimcfg_get_segment(pc, bus); | | 909 | seg = acpimcfg_get_segment(pc, bus); |
910 | if (seg == NULL) | | 910 | if (seg == NULL) |
911 | return ERANGE; | | 911 | return ERANGE; |
912 | | | 912 | |
913 | mb = &seg->ms_bus[bus - seg->ms_bus_start]; | | 913 | mb = &seg->ms_bus[bus - seg->ms_bus_start]; |
914 | if (!PCIDEV_IS_VALID(mb, dev, func)) | | 914 | if (!PCIDEV_IS_VALID(mb, dev, func)) |
915 | return EINVAL; | | 915 | return EINVAL; |
916 | if (!EXTCONF_IS_VALID(mb, dev, func) && reg >= PCI_CONF_SIZE) | | 916 | if (!EXTCONF_IS_VALID(mb, dev, func) && reg >= PCI_CONF_SIZE) |
917 | return EINVAL; | | 917 | return EINVAL; |
918 | | | 918 | |
919 | mcfg_ops->ao_write(seg->ms_bst, mb->bsh[dev][func], reg, data); | | 919 | mcfg_ops->ao_write(seg->ms_bst, mb->bsh[dev][func], reg, data); |
920 | return 0; | | 920 | return 0; |
921 | } | | 921 | } |
922 | | | 922 | |
923 | bool | | 923 | bool |
924 | acpimcfg_conf_valid(pci_chipset_tag_t pc, pcitag_t tag, int reg) | | 924 | acpimcfg_conf_valid(pci_chipset_tag_t pc, pcitag_t tag, int reg) |
925 | { | | 925 | { |
926 | struct mcfg_segment *seg = NULL; | | 926 | struct mcfg_segment *seg = NULL; |
927 | struct mcfg_bus *mb; | | 927 | struct mcfg_bus *mb; |
928 | int bus, dev, func; | | 928 | int bus, dev, func; |
929 | | | 929 | |
930 | if (!mcfg_inited) | | 930 | if (!mcfg_inited) |
931 | return false; | | 931 | return false; |
932 | | | 932 | |
933 | pci_decompose_tag(pc, tag, &bus, &dev, &func); | | 933 | pci_decompose_tag(pc, tag, &bus, &dev, &func); |
934 | | | 934 | |
935 | seg = acpimcfg_get_segment(pc, bus); | | 935 | seg = acpimcfg_get_segment(pc, bus); |
936 | if (seg == NULL) | | 936 | if (seg == NULL) |
937 | return false; | | 937 | return false; |
938 | | | 938 | |
939 | mb = &seg->ms_bus[bus - seg->ms_bus_start]; | | 939 | mb = &seg->ms_bus[bus - seg->ms_bus_start]; |
940 | if (!PCIDEV_IS_VALID(mb, dev, func)) | | 940 | if (!PCIDEV_IS_VALID(mb, dev, func)) |
941 | return false; | | 941 | return false; |
942 | if (!EXTCONF_IS_VALID(mb, dev, func) && reg >= PCI_CONF_SIZE) | | 942 | if (!EXTCONF_IS_VALID(mb, dev, func) && reg >= PCI_CONF_SIZE) |
943 | return false; | | 943 | return false; |
944 | | | 944 | |
945 | return true; | | 945 | return true; |
946 | } | | 946 | } |