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