Home | History | Annotate | Line # | Download | only in acpi
acpi_mcfg.c revision 1.3
      1  1.3   hannken /*	$NetBSD: acpi_mcfg.c,v 1.3 2016/07/12 09:29:32 hannken Exp $	*/
      2  1.1   msaitoh 
      3  1.1   msaitoh /*-
      4  1.1   msaitoh  * Copyright (C) 2015 NONAKA Kimihiro <nonaka (at) NetBSD.org>
      5  1.1   msaitoh  * All rights reserved.
      6  1.1   msaitoh  *
      7  1.1   msaitoh  * Redistribution and use in source and binary forms, with or without
      8  1.1   msaitoh  * modification, are permitted provided that the following conditions
      9  1.1   msaitoh  * are met:
     10  1.1   msaitoh  * 1. Redistributions of source code must retain the above copyright
     11  1.1   msaitoh  *    notice, this list of conditions and the following disclaimer.
     12  1.1   msaitoh  * 2. Redistributions in binary form must reproduce the above copyright
     13  1.1   msaitoh  *    notice, this list of conditions and the following disclaimer in the
     14  1.1   msaitoh  *    documentation and/or other materials provided with the distribution.
     15  1.1   msaitoh  *
     16  1.1   msaitoh  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
     17  1.1   msaitoh  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
     18  1.1   msaitoh  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
     19  1.1   msaitoh  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
     20  1.1   msaitoh  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
     21  1.1   msaitoh  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     22  1.1   msaitoh  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     23  1.1   msaitoh  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     24  1.1   msaitoh  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
     25  1.1   msaitoh  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     26  1.1   msaitoh  */
     27  1.1   msaitoh 
     28  1.1   msaitoh #include <sys/cdefs.h>
     29  1.3   hannken __KERNEL_RCSID(0, "$NetBSD: acpi_mcfg.c,v 1.3 2016/07/12 09:29:32 hannken Exp $");
     30  1.1   msaitoh 
     31  1.1   msaitoh #include <sys/param.h>
     32  1.1   msaitoh #include <sys/device.h>
     33  1.1   msaitoh #include <sys/kmem.h>
     34  1.1   msaitoh #include <sys/systm.h>
     35  1.1   msaitoh 
     36  1.1   msaitoh #include <dev/pci/pcireg.h>
     37  1.1   msaitoh #include <dev/pci/pcivar.h>
     38  1.1   msaitoh #include <dev/pci/pcidevs.h>
     39  1.1   msaitoh 
     40  1.1   msaitoh #include <dev/acpi/acpireg.h>
     41  1.1   msaitoh #include <dev/acpi/acpivar.h>
     42  1.1   msaitoh #include <dev/acpi/acpi_mcfg.h>
     43  1.1   msaitoh 
     44  1.1   msaitoh #include "locators.h"
     45  1.1   msaitoh 
     46  1.2  christos #define _COMPONENT      ACPI_RESOURCE_COMPONENT
     47  1.2  christos ACPI_MODULE_NAME	("acpi_mcfg")
     48  1.2  christos 
     49  1.1   msaitoh #define	EXTCONF_OFFSET(d, f, r)	((((d) * 8 + (f)) * PCI_EXTCONF_SIZE) + (r))
     50  1.1   msaitoh 
     51  1.1   msaitoh #define	EXTCONF_SET_VALID(mb, d, f)	((mb)->valid_devs[(d)] |= __BIT((f)))
     52  1.1   msaitoh #define	EXTCONF_SET_INVALID(mb, d, f)	((mb)->valid_devs[(d)] &= ~__BIT((f)))
     53  1.1   msaitoh #define	EXTCONF_IS_VALID(mb, d, f)	((mb)->valid_devs[(d)] & __BIT((f)))
     54  1.1   msaitoh 
     55  1.1   msaitoh struct mcfg_segment {
     56  1.1   msaitoh 	uint64_t ms_address;		/* Base address */
     57  1.1   msaitoh 	int ms_segment;			/* Segment # */
     58  1.1   msaitoh 	int ms_bus_start;		/* Start bus # */
     59  1.1   msaitoh 	int ms_bus_end;			/* End bus # */
     60  1.1   msaitoh 	bus_space_tag_t ms_bst;
     61  1.1   msaitoh 	struct mcfg_bus {
     62  1.1   msaitoh 		bus_space_handle_t bsh[32][8];
     63  1.1   msaitoh 		uint8_t valid_devs[32];
     64  1.1   msaitoh 		int valid_ndevs;
     65  1.1   msaitoh 		pcitag_t last_probed;
     66  1.1   msaitoh 	} *ms_bus;
     67  1.1   msaitoh };
     68  1.1   msaitoh 
     69  1.1   msaitoh static struct mcfg_segment *mcfg_segs;
     70  1.1   msaitoh static int mcfg_nsegs;
     71  1.1   msaitoh static ACPI_TABLE_MCFG *mcfg;
     72  1.1   msaitoh static int mcfg_inited;
     73  1.1   msaitoh static struct acpi_softc *acpi_sc;
     74  1.1   msaitoh 
     75  1.1   msaitoh static const struct acpimcfg_ops mcfg_default_ops = {
     76  1.1   msaitoh 	.ao_validate = acpimcfg_default_validate,
     77  1.1   msaitoh 
     78  1.1   msaitoh 	.ao_read = acpimcfg_default_read,
     79  1.1   msaitoh 	.ao_write = acpimcfg_default_write,
     80  1.1   msaitoh };
     81  1.1   msaitoh static const struct acpimcfg_ops *mcfg_ops = &mcfg_default_ops;
     82  1.1   msaitoh 
     83  1.1   msaitoh /*
     84  1.1   msaitoh  * default operations.
     85  1.1   msaitoh  */
     86  1.1   msaitoh bool
     87  1.1   msaitoh acpimcfg_default_validate(uint64_t address, int bus_start, int *bus_end)
     88  1.1   msaitoh {
     89  1.1   msaitoh 
     90  1.1   msaitoh 	/* Always Ok */
     91  1.1   msaitoh 	return true;
     92  1.1   msaitoh }
     93  1.1   msaitoh 
     94  1.1   msaitoh uint32_t
     95  1.1   msaitoh acpimcfg_default_read(bus_space_tag_t bst, bus_space_handle_t bsh,
     96  1.1   msaitoh     bus_addr_t addr)
     97  1.1   msaitoh {
     98  1.1   msaitoh 
     99  1.1   msaitoh 	return bus_space_read_4(bst, bsh, addr);
    100  1.1   msaitoh }
    101  1.1   msaitoh 
    102  1.1   msaitoh void
    103  1.1   msaitoh acpimcfg_default_write(bus_space_tag_t bst, bus_space_handle_t bsh,
    104  1.1   msaitoh     bus_addr_t addr, uint32_t data)
    105  1.1   msaitoh {
    106  1.1   msaitoh 
    107  1.1   msaitoh 	bus_space_write_4(bst, bsh, addr, data);
    108  1.1   msaitoh }
    109  1.1   msaitoh 
    110  1.1   msaitoh 
    111  1.1   msaitoh /*
    112  1.1   msaitoh  * Check MCFG memory region at system resource
    113  1.1   msaitoh  */
    114  1.1   msaitoh struct acpimcfg_memrange {
    115  1.1   msaitoh 	const char	*hid;
    116  1.1   msaitoh 	uint64_t	address;
    117  1.1   msaitoh 	int		bus_start;
    118  1.1   msaitoh 	int		bus_end;
    119  1.1   msaitoh 	bool		found;
    120  1.1   msaitoh };
    121  1.1   msaitoh 
    122  1.1   msaitoh static ACPI_STATUS
    123  1.1   msaitoh acpimcfg_parse_callback(ACPI_RESOURCE *res, void *ctx)
    124  1.1   msaitoh {
    125  1.1   msaitoh 	struct acpimcfg_memrange *mr = ctx;
    126  1.1   msaitoh 	const char *type;
    127  1.1   msaitoh 	uint64_t size, mapaddr, mapsize;
    128  1.1   msaitoh 	int n;
    129  1.1   msaitoh 
    130  1.1   msaitoh 	switch (res->Type) {
    131  1.1   msaitoh 	case ACPI_RESOURCE_TYPE_FIXED_MEMORY32:
    132  1.1   msaitoh 		type = "FIXED_MEMORY32";
    133  1.1   msaitoh 		mapaddr = res->Data.FixedMemory32.Address;
    134  1.1   msaitoh 		mapsize = res->Data.FixedMemory32.AddressLength;
    135  1.1   msaitoh 		break;
    136  1.1   msaitoh 
    137  1.1   msaitoh 	case ACPI_RESOURCE_TYPE_ADDRESS32:
    138  1.1   msaitoh 		/* XXX Only fixed size supported for now */
    139  1.1   msaitoh 		if (res->Data.Address32.Address.AddressLength == 0 ||
    140  1.1   msaitoh 		    res->Data.Address32.ProducerConsumer != ACPI_CONSUMER)
    141  1.1   msaitoh 			goto out;
    142  1.1   msaitoh 
    143  1.1   msaitoh 		if (res->Data.Address32.ResourceType != ACPI_MEMORY_RANGE)
    144  1.1   msaitoh 			goto out;
    145  1.1   msaitoh 
    146  1.1   msaitoh 		if (res->Data.Address32.MinAddressFixed != ACPI_ADDRESS_FIXED ||
    147  1.1   msaitoh 		    res->Data.Address32.MaxAddressFixed != ACPI_ADDRESS_FIXED)
    148  1.1   msaitoh 			goto out;
    149  1.1   msaitoh 
    150  1.1   msaitoh 		type = "ADDRESS32";
    151  1.1   msaitoh 		mapaddr = res->Data.Address32.Address.Minimum;
    152  1.1   msaitoh 		mapsize = res->Data.Address32.Address.AddressLength;
    153  1.1   msaitoh 		break;
    154  1.1   msaitoh 
    155  1.1   msaitoh #ifdef _LP64
    156  1.1   msaitoh 	case ACPI_RESOURCE_TYPE_ADDRESS64:
    157  1.1   msaitoh 		/* XXX Only fixed size supported for now */
    158  1.1   msaitoh 		if (res->Data.Address64.Address.AddressLength == 0 ||
    159  1.1   msaitoh 		    res->Data.Address64.ProducerConsumer != ACPI_CONSUMER)
    160  1.1   msaitoh 			goto out;
    161  1.1   msaitoh 
    162  1.1   msaitoh 		if (res->Data.Address64.ResourceType != ACPI_MEMORY_RANGE)
    163  1.1   msaitoh 			goto out;
    164  1.1   msaitoh 
    165  1.1   msaitoh 		if (res->Data.Address64.MinAddressFixed != ACPI_ADDRESS_FIXED ||
    166  1.1   msaitoh 		    res->Data.Address64.MaxAddressFixed != ACPI_ADDRESS_FIXED)
    167  1.1   msaitoh 			goto out;
    168  1.1   msaitoh 
    169  1.1   msaitoh 		type = "ADDRESS64";
    170  1.1   msaitoh 		mapaddr = res->Data.Address64.Address.Minimum;
    171  1.1   msaitoh 		mapsize = res->Data.Address64.Address.AddressLength;
    172  1.1   msaitoh 		break;
    173  1.1   msaitoh #endif
    174  1.1   msaitoh 
    175  1.1   msaitoh 	default:
    176  1.1   msaitoh  out:
    177  1.1   msaitoh 		aprint_debug_dev(acpi_sc->sc_dev, "MCFG: %s: Type=%d\n",
    178  1.1   msaitoh 		    mr->hid, res->Type);
    179  1.1   msaitoh 		return_ACPI_STATUS(AE_OK);
    180  1.1   msaitoh 	}
    181  1.1   msaitoh 
    182  1.1   msaitoh 	aprint_debug_dev(acpi_sc->sc_dev, "MCFG: %s: Type=%d(%s), "
    183  1.1   msaitoh 	    "Address=0x%016" PRIx64 ", Length=0x%016" PRIx64 "\n",
    184  1.1   msaitoh 	    mr->hid, res->Type, type, mapaddr, mapsize);
    185  1.1   msaitoh 
    186  1.1   msaitoh 	if (mr->address < mapaddr || mr->address >= mapaddr + mapsize)
    187  1.1   msaitoh 		return_ACPI_STATUS(AE_OK);
    188  1.1   msaitoh 
    189  1.1   msaitoh 	size = (mr->bus_end - mr->bus_start + 1) * ACPIMCFG_SIZE_PER_BUS;
    190  1.1   msaitoh 
    191  1.1   msaitoh 	/* full map */
    192  1.1   msaitoh 	if (mr->address + size <= mapaddr + mapsize) {
    193  1.1   msaitoh 		mr->found = true;
    194  1.1   msaitoh 		return_ACPI_STATUS(AE_CTRL_TERMINATE);
    195  1.1   msaitoh 	}
    196  1.1   msaitoh 
    197  1.1   msaitoh 	/* partial map */
    198  1.1   msaitoh 	n = (mapsize - (mr->address - mapaddr)) / ACPIMCFG_SIZE_PER_BUS;
    199  1.1   msaitoh 	/* bus_start == bus_end is not allowed. */
    200  1.1   msaitoh 	if (n > 1) {
    201  1.1   msaitoh 		mr->bus_end = mr->bus_start + n - 1;
    202  1.1   msaitoh 		mr->found = true;
    203  1.1   msaitoh 		return_ACPI_STATUS(AE_CTRL_TERMINATE);
    204  1.1   msaitoh 	}
    205  1.1   msaitoh 
    206  1.1   msaitoh 	aprint_debug_dev(acpi_sc->sc_dev, "MCFG: bus %d-%d, "
    207  1.1   msaitoh 	    "address 0x%016" PRIx64 ": invalid size: request 0x%016" PRIx64
    208  1.1   msaitoh 	    ", actual 0x%016" PRIx64 "\n",
    209  1.1   msaitoh 	    mr->bus_start, mr->bus_end, mr->address, size, mapsize);
    210  1.1   msaitoh 
    211  1.1   msaitoh 	return_ACPI_STATUS(AE_OK);
    212  1.1   msaitoh }
    213  1.1   msaitoh 
    214  1.1   msaitoh static ACPI_STATUS
    215  1.1   msaitoh acpimcfg_check_system_resource(ACPI_HANDLE handle, UINT32 level, void *ctx,
    216  1.1   msaitoh     void **retval)
    217  1.1   msaitoh {
    218  1.1   msaitoh 	struct acpimcfg_memrange *mr = ctx;
    219  1.1   msaitoh 	ACPI_STATUS status;
    220  1.1   msaitoh 
    221  1.1   msaitoh 	status = AcpiWalkResources(handle, "_CRS", acpimcfg_parse_callback, mr);
    222  1.1   msaitoh 	if (ACPI_FAILURE(status))
    223  1.1   msaitoh 		return_ACPI_STATUS(status);
    224  1.1   msaitoh 
    225  1.1   msaitoh 	if (mr->found)
    226  1.1   msaitoh 		return_ACPI_STATUS(AE_CTRL_TERMINATE);
    227  1.1   msaitoh 
    228  1.1   msaitoh 	aprint_debug_dev(acpi_sc->sc_dev, "MCFG: %s: bus %d-%d, "
    229  1.1   msaitoh 	    "address 0x%016" PRIx64 ": no valid region\n", mr->hid,
    230  1.1   msaitoh 	    mr->bus_start, mr->bus_end, mr->address);
    231  1.1   msaitoh 
    232  1.1   msaitoh 	return_ACPI_STATUS(AE_OK);
    233  1.1   msaitoh }
    234  1.1   msaitoh 
    235  1.1   msaitoh static bool
    236  1.1   msaitoh acpimcfg_find_system_resource(uint64_t address, int bus_start, int *bus_end)
    237  1.1   msaitoh {
    238  1.1   msaitoh 	static const char *system_resource_hid[] = {
    239  1.1   msaitoh 		"PNP0C01",	/* System Board */
    240  1.1   msaitoh 		"PNP0C02"	/* General ID for reserving resources */
    241  1.1   msaitoh 	};
    242  1.1   msaitoh 	struct acpimcfg_memrange mr;
    243  1.1   msaitoh 	ACPI_STATUS status;
    244  1.1   msaitoh 	int i;
    245  1.1   msaitoh 
    246  1.1   msaitoh 	mr.address = address;
    247  1.1   msaitoh 	mr.bus_start = bus_start;
    248  1.1   msaitoh 	mr.bus_end = *bus_end;
    249  1.1   msaitoh 	mr.found = false;
    250  1.1   msaitoh 
    251  1.1   msaitoh 	for (i = 0; i < __arraycount(system_resource_hid); i++) {
    252  1.1   msaitoh 		mr.hid = system_resource_hid[i];
    253  1.1   msaitoh 		status = AcpiGetDevices(__UNCONST(system_resource_hid[i]),
    254  1.1   msaitoh 		    acpimcfg_check_system_resource, &mr, NULL);
    255  1.1   msaitoh 		if (ACPI_FAILURE(status))
    256  1.1   msaitoh 			continue;
    257  1.1   msaitoh 		if (mr.found) {
    258  1.1   msaitoh 			*bus_end = mr.bus_end;
    259  1.1   msaitoh 			return true;
    260  1.1   msaitoh 		}
    261  1.1   msaitoh 	}
    262  1.1   msaitoh 	return false;
    263  1.1   msaitoh }
    264  1.1   msaitoh 
    265  1.1   msaitoh 
    266  1.1   msaitoh /*
    267  1.1   msaitoh  * ACPI MCFG
    268  1.1   msaitoh  */
    269  1.1   msaitoh void
    270  1.1   msaitoh acpimcfg_probe(struct acpi_softc *sc)
    271  1.1   msaitoh {
    272  1.1   msaitoh 	ACPI_MCFG_ALLOCATION *ama;
    273  1.1   msaitoh 	ACPI_STATUS status;
    274  1.1   msaitoh 	uint32_t offset;
    275  1.1   msaitoh 	int i, nsegs;
    276  1.1   msaitoh 
    277  1.1   msaitoh 	if (acpi_sc != NULL)
    278  1.1   msaitoh 		panic("acpi_sc != NULL");
    279  1.1   msaitoh 	acpi_sc = sc;
    280  1.1   msaitoh 
    281  1.1   msaitoh 	status = AcpiGetTable(ACPI_SIG_MCFG, 0, (ACPI_TABLE_HEADER **)&mcfg);
    282  1.1   msaitoh 	if (ACPI_FAILURE(status)) {
    283  1.1   msaitoh 		mcfg = NULL;
    284  1.1   msaitoh 		return;
    285  1.1   msaitoh 	}
    286  1.1   msaitoh 
    287  1.1   msaitoh 	nsegs = 0;
    288  1.1   msaitoh 	offset = sizeof(ACPI_TABLE_MCFG);
    289  1.1   msaitoh 	ama = ACPI_ADD_PTR(ACPI_MCFG_ALLOCATION, mcfg, offset);
    290  1.1   msaitoh 	for (i = 0; offset < mcfg->Header.Length; i++) {
    291  1.1   msaitoh 		aprint_debug_dev(sc->sc_dev,
    292  1.1   msaitoh 		    "MCFG: segment %d, bus %d-%d, address 0x%016" PRIx64 "\n",
    293  1.1   msaitoh 		    ama->PciSegment, ama->StartBusNumber, ama->EndBusNumber,
    294  1.1   msaitoh 		    ama->Address);
    295  1.1   msaitoh 		nsegs++;
    296  1.1   msaitoh 		offset += sizeof(ACPI_MCFG_ALLOCATION);
    297  1.1   msaitoh 		ama = ACPI_ADD_PTR(ACPI_MCFG_ALLOCATION, ama, offset);
    298  1.1   msaitoh 	}
    299  1.1   msaitoh 	if (nsegs == 0) {
    300  1.1   msaitoh 		mcfg = NULL;
    301  1.1   msaitoh 		return;
    302  1.1   msaitoh 	}
    303  1.1   msaitoh 
    304  1.1   msaitoh 	mcfg_segs = kmem_zalloc(sizeof(*mcfg_segs) * nsegs, KM_SLEEP);
    305  1.1   msaitoh 	mcfg_nsegs = nsegs;
    306  1.1   msaitoh }
    307  1.1   msaitoh 
    308  1.1   msaitoh int
    309  1.1   msaitoh acpimcfg_init(bus_space_tag_t memt, const struct acpimcfg_ops *ops)
    310  1.1   msaitoh {
    311  1.1   msaitoh 	ACPI_MCFG_ALLOCATION *ama;
    312  1.1   msaitoh 	struct mcfg_segment *seg;
    313  1.1   msaitoh 	uint32_t offset;
    314  1.1   msaitoh 	int i, n, nsegs, bus_end;
    315  1.1   msaitoh 
    316  1.1   msaitoh 	if (mcfg == NULL)
    317  1.1   msaitoh 		return ENXIO;
    318  1.1   msaitoh 
    319  1.1   msaitoh 	if (mcfg_inited)
    320  1.1   msaitoh 		return 0;
    321  1.1   msaitoh 
    322  1.1   msaitoh 	if (ops != NULL)
    323  1.1   msaitoh 		mcfg_ops = ops;
    324  1.1   msaitoh 
    325  1.1   msaitoh 	nsegs = 0;
    326  1.1   msaitoh 	offset = sizeof(ACPI_TABLE_MCFG);
    327  1.1   msaitoh 	ama = ACPI_ADD_PTR(ACPI_MCFG_ALLOCATION, mcfg, offset);
    328  1.1   msaitoh 	for (i = 0; offset < mcfg->Header.Length; i++) {
    329  1.1   msaitoh #ifndef _LP64
    330  1.1   msaitoh 		if (ama->Address >= 0x100000000ULL) {
    331  1.1   msaitoh 			aprint_debug_dev(acpi_sc->sc_dev,
    332  1.1   msaitoh 			    "MCFG: segment %d, bus %d-%d, address 0x%016" PRIx64
    333  1.1   msaitoh 			    ": ignore (64bit address)\n", ama->PciSegment,
    334  1.1   msaitoh 			    ama->StartBusNumber, ama->EndBusNumber,
    335  1.1   msaitoh 			    ama->Address);
    336  1.1   msaitoh 			goto next;
    337  1.1   msaitoh 		}
    338  1.1   msaitoh #endif
    339  1.1   msaitoh 		/*
    340  1.1   msaitoh 		 * Some (broken?) BIOSen have an MCFG table for an empty
    341  1.1   msaitoh 		 * bus range.  Ignore those tables.
    342  1.1   msaitoh 		 */
    343  1.1   msaitoh 		if (ama->StartBusNumber == ama->EndBusNumber) {
    344  1.1   msaitoh 			aprint_debug_dev(acpi_sc->sc_dev,
    345  1.1   msaitoh 			    "MCFG: segment %d, bus %d-%d, address 0x%016" PRIx64
    346  1.1   msaitoh 			    ": ignore (bus %d == %d)\n", ama->PciSegment,
    347  1.1   msaitoh 			    ama->StartBusNumber, ama->EndBusNumber,
    348  1.1   msaitoh 			    ama->Address, ama->StartBusNumber,
    349  1.1   msaitoh 			    ama->EndBusNumber);
    350  1.1   msaitoh 			goto next;
    351  1.1   msaitoh 		}
    352  1.1   msaitoh 		if (ama->StartBusNumber > ama->EndBusNumber) {
    353  1.1   msaitoh 			aprint_debug_dev(acpi_sc->sc_dev,
    354  1.1   msaitoh 			    "MCFG: segment %d, bus %d-%d, address 0x%016" PRIx64
    355  1.1   msaitoh 			    ": ignore (bus %d > %d)\n", ama->PciSegment,
    356  1.1   msaitoh 			    ama->StartBusNumber, ama->EndBusNumber,
    357  1.1   msaitoh 			    ama->Address, ama->StartBusNumber,
    358  1.1   msaitoh 			    ama->EndBusNumber);
    359  1.1   msaitoh 			goto next;
    360  1.1   msaitoh 		}
    361  1.1   msaitoh 
    362  1.1   msaitoh 		/* Validate MCFG memory range */
    363  1.1   msaitoh 		bus_end = ama->EndBusNumber;
    364  1.1   msaitoh 		if (mcfg_ops->ao_validate != NULL &&
    365  1.1   msaitoh 		    !mcfg_ops->ao_validate(ama->Address, ama->StartBusNumber,
    366  1.1   msaitoh 		      &bus_end)) {
    367  1.1   msaitoh 			if (!acpimcfg_find_system_resource( ama->Address,
    368  1.1   msaitoh 			    ama->StartBusNumber, &bus_end)) {
    369  1.1   msaitoh 				aprint_debug_dev(acpi_sc->sc_dev,
    370  1.1   msaitoh 				    "MCFG: segment %d, bus %d-%d, "
    371  1.1   msaitoh 				    "address 0x%016" PRIx64
    372  1.1   msaitoh 				    ": ignore (invalid address)\n",
    373  1.1   msaitoh 				    ama->PciSegment,
    374  1.1   msaitoh 				    ama->StartBusNumber, ama->EndBusNumber,
    375  1.1   msaitoh 				    ama->Address);
    376  1.1   msaitoh 				goto next;
    377  1.1   msaitoh 			}
    378  1.1   msaitoh 		}
    379  1.1   msaitoh 		if (ama->EndBusNumber != bus_end) {
    380  1.1   msaitoh 			aprint_debug_dev(acpi_sc->sc_dev,
    381  1.1   msaitoh 			    "MCFG: segment %d, bus %d-%d, address 0x%016" PRIx64
    382  1.1   msaitoh 			    " -> bus %d-%d\n", ama->PciSegment,
    383  1.1   msaitoh 			    ama->StartBusNumber, ama->EndBusNumber,
    384  1.1   msaitoh 			    ama->Address, ama->StartBusNumber, bus_end);
    385  1.1   msaitoh 		}
    386  1.1   msaitoh 
    387  1.1   msaitoh 		if (ama->PciSegment != 0) {
    388  1.1   msaitoh 			aprint_debug_dev(acpi_sc->sc_dev,
    389  1.1   msaitoh 			    "MCFG: segment %d, bus %d-%d, address 0x%016" PRIx64
    390  1.1   msaitoh 			    ": ignore (non PCI segment 0)\n", ama->PciSegment,
    391  1.1   msaitoh 			    ama->StartBusNumber, bus_end, ama->Address);
    392  1.1   msaitoh 			goto next;
    393  1.1   msaitoh 		}
    394  1.1   msaitoh 
    395  1.1   msaitoh 		seg = &mcfg_segs[nsegs++];
    396  1.1   msaitoh 		seg->ms_address = ama->Address;
    397  1.1   msaitoh 		seg->ms_segment = ama->PciSegment;
    398  1.1   msaitoh 		seg->ms_bus_start = ama->StartBusNumber;
    399  1.1   msaitoh 		seg->ms_bus_end = bus_end;
    400  1.1   msaitoh 		seg->ms_bst = memt;
    401  1.1   msaitoh 		n = seg->ms_bus_end - seg->ms_bus_start + 1;
    402  1.1   msaitoh 		seg->ms_bus = kmem_zalloc(sizeof(*seg->ms_bus) * n, KM_SLEEP);
    403  1.1   msaitoh 
    404  1.1   msaitoh  next:
    405  1.1   msaitoh 		offset += sizeof(ACPI_MCFG_ALLOCATION);
    406  1.1   msaitoh 		ama = ACPI_ADD_PTR(ACPI_MCFG_ALLOCATION, ama, offset);
    407  1.1   msaitoh 	}
    408  1.1   msaitoh 	if (nsegs == 0)
    409  1.1   msaitoh 		return ENOENT;
    410  1.1   msaitoh 
    411  1.1   msaitoh 	for (i = 0; i < nsegs; i++) {
    412  1.1   msaitoh 		seg = &mcfg_segs[i];
    413  1.1   msaitoh 		aprint_verbose_dev(acpi_sc->sc_dev,
    414  1.1   msaitoh 		    "MCFG: segment %d, bus %d-%d, address 0x%016" PRIx64 "\n",
    415  1.1   msaitoh 		    seg->ms_segment, seg->ms_bus_start, seg->ms_bus_end,
    416  1.1   msaitoh 		    seg->ms_address);
    417  1.1   msaitoh 	}
    418  1.1   msaitoh 
    419  1.1   msaitoh 	/* Update # of segment */
    420  1.1   msaitoh 	mcfg_nsegs = nsegs;
    421  1.1   msaitoh 	mcfg_inited = true;
    422  1.1   msaitoh 
    423  1.1   msaitoh 	return 0;
    424  1.1   msaitoh }
    425  1.1   msaitoh 
    426  1.1   msaitoh static int
    427  1.1   msaitoh acpimcfg_ext_conf_is_aliased(pci_chipset_tag_t pc, pcitag_t tag)
    428  1.1   msaitoh {
    429  1.1   msaitoh 	pcireg_t id;
    430  1.1   msaitoh 	int i;
    431  1.1   msaitoh 
    432  1.1   msaitoh 	id = pci_conf_read(pc, tag, PCI_ID_REG);
    433  1.1   msaitoh 	for (i = PCI_CONF_SIZE; i < PCI_EXTCONF_SIZE; i += PCI_CONF_SIZE) {
    434  1.1   msaitoh 		if (pci_conf_read(pc, tag, i) != id)
    435  1.1   msaitoh 			return false;
    436  1.1   msaitoh 	}
    437  1.1   msaitoh 	return true;
    438  1.1   msaitoh }
    439  1.1   msaitoh 
    440  1.1   msaitoh static struct mcfg_segment *
    441  1.1   msaitoh acpimcfg_get_segment(int bus)
    442  1.1   msaitoh {
    443  1.1   msaitoh 	struct mcfg_segment *seg;
    444  1.1   msaitoh 	int i;
    445  1.1   msaitoh 
    446  1.1   msaitoh 	for (i = 0; i < mcfg_nsegs; i++) {
    447  1.1   msaitoh 		seg = &mcfg_segs[i];
    448  1.1   msaitoh 		if (bus >= seg->ms_bus_start && bus <= seg->ms_bus_end)
    449  1.1   msaitoh 			return seg;
    450  1.1   msaitoh 	}
    451  1.1   msaitoh 	return NULL;
    452  1.1   msaitoh }
    453  1.1   msaitoh 
    454  1.1   msaitoh static int
    455  1.1   msaitoh acpimcfg_device_probe(const struct pci_attach_args *pa)
    456  1.1   msaitoh {
    457  1.1   msaitoh 	pci_chipset_tag_t pc = pa->pa_pc;
    458  1.1   msaitoh 	struct mcfg_segment *seg;
    459  1.1   msaitoh 	struct mcfg_bus *mb;
    460  1.1   msaitoh 	pcitag_t tag;
    461  1.1   msaitoh 	pcireg_t reg;
    462  1.1   msaitoh 	int bus = pa->pa_bus;
    463  1.1   msaitoh 	int dev = pa->pa_device;
    464  1.1   msaitoh 	int func = pa->pa_function;
    465  1.1   msaitoh 	int last_dev, last_func, end_func;
    466  1.1   msaitoh 	int alias = 0;
    467  1.1   msaitoh 	int i, j;
    468  1.1   msaitoh 
    469  1.1   msaitoh 	seg = acpimcfg_get_segment(bus);
    470  1.1   msaitoh 	if (seg == NULL)
    471  1.1   msaitoh 		return 0;
    472  1.1   msaitoh 
    473  1.1   msaitoh 	mb = &seg->ms_bus[bus - seg->ms_bus_start];
    474  1.1   msaitoh 	tag = pci_make_tag(pc, bus, dev, func);
    475  1.1   msaitoh 
    476  1.1   msaitoh 	/* Mark invalid between last probed device to probed device. */
    477  1.1   msaitoh 	pci_decompose_tag(pc, mb->last_probed, NULL, &last_dev, &last_func);
    478  1.1   msaitoh 	if (dev != 0 || func != 0) {
    479  1.1   msaitoh 		for (i = last_dev; i <= dev; i++) {
    480  1.1   msaitoh 			end_func = (i == dev) ? func : 8;
    481  1.1   msaitoh 			for (j = last_func; j < end_func; j++) {
    482  1.1   msaitoh 				if (i == last_dev && j == last_func)
    483  1.1   msaitoh 					continue;
    484  1.1   msaitoh 				EXTCONF_SET_INVALID(mb, i, j);
    485  1.1   msaitoh 			}
    486  1.1   msaitoh 			last_func = 0;
    487  1.1   msaitoh 		}
    488  1.1   msaitoh 	}
    489  1.1   msaitoh 	mb->last_probed = tag;
    490  1.1   msaitoh 
    491  1.1   msaitoh 	/* Probe extended configuration space. */
    492  1.1   msaitoh 	if (((reg = pci_conf_read(pc, tag, PCI_CONF_SIZE)) == (pcireg_t)-1) ||
    493  1.1   msaitoh 	    (alias = acpimcfg_ext_conf_is_aliased(pc, tag))) {
    494  1.1   msaitoh 		aprint_debug_dev(acpi_sc->sc_dev,
    495  1.1   msaitoh 		    "MCFG: %03d:%02d:%d: invalid config space "
    496  1.1   msaitoh 		    "(cfg[0x%03x]=0x%08x, alias=%s)\n", bus, dev, func,
    497  1.1   msaitoh 		    PCI_CONF_SIZE, reg, alias ? "true" : "false");
    498  1.1   msaitoh 		EXTCONF_SET_INVALID(mb, dev, func);
    499  1.1   msaitoh 	} else {
    500  1.1   msaitoh 		aprint_debug_dev(acpi_sc->sc_dev,
    501  1.1   msaitoh 		    "MCFG: %03d:%02d:%d: Ok (cfg[0x%03x]=0x%08x)\n",
    502  1.1   msaitoh 		    bus, dev, func, PCI_CONF_SIZE, reg);
    503  1.1   msaitoh 		mb->valid_ndevs++;
    504  1.1   msaitoh 	}
    505  1.1   msaitoh 
    506  1.1   msaitoh 	return 0;
    507  1.1   msaitoh }
    508  1.1   msaitoh 
    509  1.1   msaitoh static void
    510  1.1   msaitoh acpimcfg_scan_bus(struct pci_softc *sc, pci_chipset_tag_t pc, int bus)
    511  1.1   msaitoh {
    512  1.1   msaitoh 	static const int wildcard[PCICF_NLOCS] = {
    513  1.1   msaitoh 		PCICF_DEV_DEFAULT, PCICF_FUNCTION_DEFAULT
    514  1.1   msaitoh 	};
    515  1.1   msaitoh 
    516  1.1   msaitoh 	sc->sc_bus = bus;	/* XXX */
    517  1.1   msaitoh 
    518  1.1   msaitoh 	pci_enumerate_bus(sc, wildcard, acpimcfg_device_probe, NULL);
    519  1.1   msaitoh }
    520  1.1   msaitoh 
    521  1.1   msaitoh int
    522  1.1   msaitoh acpimcfg_map_bus(device_t self, pci_chipset_tag_t pc, int bus)
    523  1.1   msaitoh {
    524  1.1   msaitoh 	struct pci_softc *sc = device_private(self);
    525  1.1   msaitoh 	struct mcfg_segment *seg = NULL;
    526  1.1   msaitoh 	struct mcfg_bus *mb;
    527  1.1   msaitoh 	bus_space_handle_t bsh;
    528  1.1   msaitoh 	bus_addr_t baddr;
    529  1.3   hannken 	pcitag_t tag;
    530  1.3   hannken 	pcireg_t reg;
    531  1.3   hannken 	bool is_e7520_mch;
    532  1.1   msaitoh 	int boff;
    533  1.1   msaitoh 	int last_dev, last_func;
    534  1.1   msaitoh 	int i, j;
    535  1.1   msaitoh 	int error;
    536  1.1   msaitoh 
    537  1.1   msaitoh 	if (!mcfg_inited)
    538  1.1   msaitoh 		return ENXIO;
    539  1.1   msaitoh 
    540  1.1   msaitoh 	seg = acpimcfg_get_segment(bus);
    541  1.1   msaitoh 	if (seg == NULL)
    542  1.1   msaitoh 		return ENOENT;
    543  1.1   msaitoh 
    544  1.1   msaitoh 	boff = bus - seg->ms_bus_start;
    545  1.1   msaitoh 	if (seg->ms_bus[boff].valid_ndevs > 0)
    546  1.1   msaitoh 		return 0;
    547  1.1   msaitoh 
    548  1.1   msaitoh 	mb = &seg->ms_bus[boff];
    549  1.1   msaitoh 	baddr = seg->ms_address + (boff * ACPIMCFG_SIZE_PER_BUS);
    550  1.1   msaitoh 
    551  1.1   msaitoh 	/* Map extended configration space of all dev/func. */
    552  1.1   msaitoh 	error = bus_space_map(seg->ms_bst, baddr, ACPIMCFG_SIZE_PER_BUS, 0,
    553  1.1   msaitoh 	    &bsh);
    554  1.1   msaitoh 	if (error != 0)
    555  1.1   msaitoh 		return error;
    556  1.1   msaitoh 	for (i = 0; i < 32; i++) {
    557  1.1   msaitoh 		for (j = 0; j < 8; j++) {
    558  1.1   msaitoh 			error = bus_space_subregion(seg->ms_bst, bsh,
    559  1.1   msaitoh 			    EXTCONF_OFFSET(i, j, 0), PCI_EXTCONF_SIZE,
    560  1.1   msaitoh 			    &mb->bsh[i][j]);
    561  1.1   msaitoh 			if (error != 0)
    562  1.1   msaitoh 				break;
    563  1.1   msaitoh 		}
    564  1.1   msaitoh 	}
    565  1.1   msaitoh 	if (error != 0)
    566  1.1   msaitoh 		return error;
    567  1.1   msaitoh 
    568  1.1   msaitoh 	aprint_debug("\n");
    569  1.1   msaitoh 
    570  1.1   msaitoh 	/* Probe extended configuration space of all devices. */
    571  1.1   msaitoh 	memset(mb->valid_devs, 0xff, sizeof(mb->valid_devs));
    572  1.1   msaitoh 	mb->valid_ndevs = 0;
    573  1.1   msaitoh 	mb->last_probed = pci_make_tag(pc, bus, 0, 0);
    574  1.1   msaitoh 
    575  1.3   hannken 	/*
    576  1.3   hannken 	 * On an Intel E7520 we have to temporarily disable
    577  1.3   hannken 	 * Enhanced Config Access error detection and reporting
    578  1.3   hannken 	 * by setting the appropriate error mask in HI_ERRMASK register.
    579  1.3   hannken 	 *
    580  1.3   hannken 	 * See "Intel E7520 Memory Controller Hub (MCH) Datasheet",
    581  1.3   hannken 	 * Document 303006-002, pg. 82
    582  1.3   hannken 	 */
    583  1.3   hannken 	tag = pci_make_tag(pc, 0, 0, 1);
    584  1.3   hannken 	reg = pci_conf_read(pc, tag, PCI_ID_REG);
    585  1.3   hannken 	is_e7520_mch = (reg ==
    586  1.3   hannken 	    PCI_ID_CODE(PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_E7525_MCHER));
    587  1.3   hannken 	if (is_e7520_mch) {
    588  1.3   hannken 		reg = pci_conf_read(pc, tag, 0x54);
    589  1.3   hannken 		pci_conf_write(pc, tag, 0x54, reg | 0x20);
    590  1.3   hannken 	}
    591  1.3   hannken 
    592  1.1   msaitoh 	acpimcfg_scan_bus(sc, pc, bus);
    593  1.1   msaitoh 
    594  1.3   hannken 	if (is_e7520_mch) {
    595  1.3   hannken 		pci_conf_write(pc, tag, 0x54, reg);
    596  1.3   hannken 	}
    597  1.3   hannken 
    598  1.1   msaitoh 	/* Unmap extended configration space of all dev/func. */
    599  1.1   msaitoh 	bus_space_unmap(seg->ms_bst, bsh, ACPIMCFG_SIZE_PER_BUS);
    600  1.1   msaitoh 	memset(mb->bsh, 0, sizeof(mb->bsh));
    601  1.1   msaitoh 
    602  1.1   msaitoh 	if (mb->valid_ndevs == 0) {
    603  1.1   msaitoh 		aprint_debug_dev(acpi_sc->sc_dev,
    604  1.1   msaitoh 		    "MCFG: bus %d: no valid devices.\n", bus);
    605  1.1   msaitoh 		memset(mb->valid_devs, 0, sizeof(mb->valid_devs));
    606  1.1   msaitoh 		goto out;
    607  1.1   msaitoh 	}
    608  1.1   msaitoh 
    609  1.1   msaitoh 	/* Mark invalid on remaining all devices. */
    610  1.1   msaitoh 	pci_decompose_tag(pc, mb->last_probed, NULL, &last_dev, &last_func);
    611  1.1   msaitoh 	for (i = last_dev; i < 32; i++) {
    612  1.1   msaitoh 		for (j = last_func; j < 8; j++) {
    613  1.1   msaitoh 			if (i == last_dev && j == last_func) {
    614  1.1   msaitoh 				/* Don't mark invalid to last probed device. */
    615  1.1   msaitoh 				continue;
    616  1.1   msaitoh 			}
    617  1.1   msaitoh 			EXTCONF_SET_INVALID(mb, i, j);
    618  1.1   msaitoh 		}
    619  1.1   msaitoh 		last_func = 0;
    620  1.1   msaitoh 	}
    621  1.1   msaitoh 
    622  1.1   msaitoh 	/* Map extended configuration space per dev/func. */
    623  1.1   msaitoh 	for (i = 0; i < 32; i++) {
    624  1.1   msaitoh 		for (j = 0; j < 8; j++) {
    625  1.1   msaitoh 			if (!EXTCONF_IS_VALID(mb, i, j))
    626  1.1   msaitoh 				continue;
    627  1.1   msaitoh 			error = bus_space_map(seg->ms_bst,
    628  1.1   msaitoh 			    baddr + EXTCONF_OFFSET(i, j, 0), PCI_EXTCONF_SIZE,
    629  1.1   msaitoh 			    0, &mb->bsh[i][j]);
    630  1.1   msaitoh 			if (error != 0) {
    631  1.1   msaitoh 				/* Unmap all handles when map failed. */
    632  1.1   msaitoh 				do {
    633  1.1   msaitoh 					while (--j >= 0) {
    634  1.1   msaitoh 						if (!EXTCONF_IS_VALID(mb, i, j))
    635  1.1   msaitoh 							continue;
    636  1.1   msaitoh 						bus_space_unmap(seg->ms_bst,
    637  1.1   msaitoh 						    mb->bsh[i][j],
    638  1.1   msaitoh 						    PCI_EXTCONF_SIZE);
    639  1.1   msaitoh 					}
    640  1.1   msaitoh 					j = 8;
    641  1.1   msaitoh 				} while (--i >= 0);
    642  1.1   msaitoh 				memset(mb->valid_devs, 0,
    643  1.1   msaitoh 				    sizeof(mb->valid_devs));
    644  1.1   msaitoh 				goto out;
    645  1.1   msaitoh 			}
    646  1.1   msaitoh 		}
    647  1.1   msaitoh 	}
    648  1.1   msaitoh 
    649  1.1   msaitoh 	aprint_debug_dev(acpi_sc->sc_dev, "MCFG: bus %d: valid devices\n", bus);
    650  1.1   msaitoh 	for (i = 0; i < 32; i++) {
    651  1.1   msaitoh 		for (j = 0; j < 8; j++) {
    652  1.1   msaitoh 			if (EXTCONF_IS_VALID(mb, i, j)) {
    653  1.1   msaitoh 				aprint_debug_dev(acpi_sc->sc_dev,
    654  1.1   msaitoh 				    "MCFG: %03d:%02d:%d\n", bus, i, j);
    655  1.1   msaitoh 			}
    656  1.1   msaitoh 		}
    657  1.1   msaitoh 	}
    658  1.1   msaitoh 
    659  1.1   msaitoh 	error = 0;
    660  1.1   msaitoh out:
    661  1.1   msaitoh 	aprint_debug_dev(acpi_sc->sc_dev, "%s done", __func__);
    662  1.1   msaitoh 
    663  1.1   msaitoh 	return error;
    664  1.1   msaitoh }
    665  1.1   msaitoh 
    666  1.1   msaitoh int
    667  1.1   msaitoh acpimcfg_conf_read(pci_chipset_tag_t pc, pcitag_t tag, int reg, pcireg_t *data)
    668  1.1   msaitoh {
    669  1.1   msaitoh 	struct mcfg_segment *seg = NULL;
    670  1.1   msaitoh 	struct mcfg_bus *mb;
    671  1.1   msaitoh 	int bus, dev, func;
    672  1.1   msaitoh 
    673  1.1   msaitoh 	KASSERT(reg < PCI_EXTCONF_SIZE);
    674  1.1   msaitoh 	KASSERT((reg & 3) == 0);
    675  1.1   msaitoh 
    676  1.1   msaitoh 	if (!mcfg_inited) {
    677  1.1   msaitoh 		*data = -1;
    678  1.1   msaitoh 		return ENXIO;
    679  1.1   msaitoh 	}
    680  1.1   msaitoh 
    681  1.1   msaitoh 	pci_decompose_tag(pc, tag, &bus, &dev, &func);
    682  1.1   msaitoh 
    683  1.1   msaitoh 	seg = acpimcfg_get_segment(bus);
    684  1.1   msaitoh 	if (seg == NULL) {
    685  1.1   msaitoh 		*data = -1;
    686  1.1   msaitoh 		return ERANGE;
    687  1.1   msaitoh 	}
    688  1.1   msaitoh 
    689  1.1   msaitoh 	mb = &seg->ms_bus[bus - seg->ms_bus_start];
    690  1.1   msaitoh 	if (!EXTCONF_IS_VALID(mb, dev, func)) {
    691  1.1   msaitoh 		*data = -1;
    692  1.1   msaitoh 		return EINVAL;
    693  1.1   msaitoh 	}
    694  1.1   msaitoh 
    695  1.1   msaitoh 	*data = mcfg_ops->ao_read(seg->ms_bst, mb->bsh[dev][func], reg);
    696  1.1   msaitoh 	return 0;
    697  1.1   msaitoh }
    698  1.1   msaitoh 
    699  1.1   msaitoh int
    700  1.1   msaitoh acpimcfg_conf_write(pci_chipset_tag_t pc, pcitag_t tag, int reg, pcireg_t data)
    701  1.1   msaitoh {
    702  1.1   msaitoh 	struct mcfg_segment *seg = NULL;
    703  1.1   msaitoh 	struct mcfg_bus *mb;
    704  1.1   msaitoh 	int bus, dev, func;
    705  1.1   msaitoh 
    706  1.1   msaitoh 	KASSERT(reg < PCI_EXTCONF_SIZE);
    707  1.1   msaitoh 	KASSERT((reg & 3) == 0);
    708  1.1   msaitoh 
    709  1.1   msaitoh 	if (!mcfg_inited)
    710  1.1   msaitoh 		return ENXIO;
    711  1.1   msaitoh 
    712  1.1   msaitoh 	pci_decompose_tag(pc, tag, &bus, &dev, &func);
    713  1.1   msaitoh 
    714  1.1   msaitoh 	seg = acpimcfg_get_segment(bus);
    715  1.1   msaitoh 	if (seg == NULL)
    716  1.1   msaitoh 		return ERANGE;
    717  1.1   msaitoh 
    718  1.1   msaitoh 	mb = &seg->ms_bus[bus - seg->ms_bus_start];
    719  1.1   msaitoh 	if (!EXTCONF_IS_VALID(mb, dev, func))
    720  1.1   msaitoh 		return EINVAL;
    721  1.1   msaitoh 
    722  1.1   msaitoh 	mcfg_ops->ao_write(seg->ms_bst, mb->bsh[dev][func], reg, data);
    723  1.1   msaitoh 	return 0;
    724  1.1   msaitoh }
    725